C#s framtida finesser (Generics under runtime)
Förord
I förra artikeln pratade jag om hur man byggde upp Generic klasser under nästa version av C# som troligen kommer i samma veva som nya SQL-Servern.Innehåll
»»
»
»
Nu tänkte jag ta upp hur dessa klasser hanteras under runtime. Ni minns väl själva instansierings syntaxen.
När en generic klass blir kompilerad så skiljer det sig inte jämfört med när en vanlig klass kompileras, allt är bara metadata och IL. Dock skilljer sig själva IL koden om man använder sig av refernes typer eller värde typer. (Value types)
När en Generic typ är skapad med en värde typ som parameter så vill runtimen skapa en specialiserad generic typ som skapas en gång per unik värde typ som används som parameter.
Vi kan ta en titt på ett exempel.
Låt säga att vi tar vår Stack exempel från tidigare artikel. För att ange att den skulle hantera int skrev vi följande:
Vad runtimen gör nu är att specialicera denna stack med värde typen int, den kommer då skapa en specialiserad generic typ i vår IL. Använder vi två stackar med integer som parameter så kommer runtimen att återanvända den specialiserade stack klassen. Alltså när vi skapar två Stackar med int som parameter så kommer båda att använda redan genererad kod under runtimen.
Om vi nu exempelvis hade skapat en till Stack klass med ett en annan värde typ som parameter så skulle runtimen skapa en ny version. Som skulle läggats till i vår IL.
Fördelen med specialiserade klasser för genrics som är skapade med värde typer
är att de ger bättre prestanda. Varför kommer ni få veta då jag nu går in på hur Generic klasser med objekt referenser better sig.
När det handlar om referens typer så arbetas det inte på samma sätt, som med värdetyper.
Varje gång man skapar en ny instans med en annan refersn typ så kommer runtimen att återanvända den specialiserade versionen som skapades senast.
Låt oss säga att vi har två referens typer, en Order (Order) klass och en Kund (Customer) klass. Vi skapar en stack klass med Kund som paramter typ,
Här kommer runtimen att skapa en specialiserad version of Stack klassen som istället för att lagra data, lagrar object referenser som kommer att fyllas i senare.
På nästa rad skapar vi en Stack klass med en annan referns typ, vår Order
Till skillnad från värde typer, så skapas inte en ny Stack klass om man skapar en med Order klassen.
För vajre objekt referens så allokeras objektet i minnet och en pekare är satt till referensen. På så vis blir de lite långsammare än Generic klasser som använder sig av värdetyper. Ungefär som skillnaden mellan Objekt klass vs Struct.
För er som använt reflections så kommer generic klasser att hanteras på exakt samma sätt som klasser gör idag.
När man skapar klasser med olika värde typer så kommer runtimen att skapa en helt ny specialiserad klass i vår IL, eller återanvända en redan befintlig med samma värde typ. Tillskillnad från referenstyper där man återanvänder den senaste specialiserade klassen, genom att peka om objekt referensen till det nya objektet. Precis som med Värde typer (int,float...) vs Refernstyper (string...) så kommer generics med värde typ att ge bättre prestanda under runtime.
Stack stack;
När en generic klass blir kompilerad så skiljer det sig inte jämfört med när en vanlig klass kompileras, allt är bara metadata och IL. Dock skilljer sig själva IL koden om man använder sig av refernes typer eller värde typer. (Value types)
Värde typer
När en Generic typ är skapad med en värde typ som parameter så vill runtimen skapa en specialiserad generic typ som skapas en gång per unik värde typ som används som parameter. Vi kan ta en titt på ett exempel.
Låt säga att vi tar vår Stack exempel från tidigare artikel. För att ange att den skulle hantera int skrev vi följande:
Stack stack = new Stack;
Vad runtimen gör nu är att specialicera denna stack med värde typen int, den kommer då skapa en specialiserad generic typ i vår IL. Använder vi två stackar med integer som parameter så kommer runtimen att återanvända den specialiserade stack klassen. Alltså när vi skapar två Stackar med int som parameter så kommer båda att använda redan genererad kod under runtimen.
Stack stackOne = new Stack;
Stack stackTwo = new Stack;
Om vi nu exempelvis hade skapat en till Stack klass med ett en annan värde typ som parameter så skulle runtimen skapa en ny version. Som skulle läggats till i vår IL.
Stack stackOne = new Stack;
Stack stackTwo = new Stack;
Fördelen med specialiserade klasser för genrics som är skapade med värde typer
är att de ger bättre prestanda. Varför kommer ni få veta då jag nu går in på hur Generic klasser med objekt referenser better sig.
Referenstyper
När det handlar om referens typer så arbetas det inte på samma sätt, som med värdetyper.Varje gång man skapar en ny instans med en annan refersn typ så kommer runtimen att återanvända den specialiserade versionen som skapades senast.
Låt oss säga att vi har två referens typer, en Order (Order) klass och en Kund (Customer) klass. Vi skapar en stack klass med Kund som paramter typ,
Stack customers;
Här kommer runtimen att skapa en specialiserad version of Stack klassen som istället för att lagra data, lagrar object referenser som kommer att fyllas i senare.
På nästa rad skapar vi en Stack klass med en annan referns typ, vår Order
Stack customers = new Stack;
Stack orders = new Stack;
Till skillnad från värde typer, så skapas inte en ny Stack klass om man skapar en med Order klassen.
För vajre objekt referens så allokeras objektet i minnet och en pekare är satt till referensen. På så vis blir de lite långsammare än Generic klasser som använder sig av värdetyper. Ungefär som skillnaden mellan Objekt klass vs Struct.
0 Kommentarer