Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
När en allmän typ eller metod kompileras till ett gemensamt mellanliggande språk (CIL) innehåller den metadata som identifierar den som att den har typparametrar. Hur CIL för en allmän typ används skiljer sig beroende på om den angivna typparametern är en värdetyp eller referenstyp.
När en allmän typ först konstrueras med en värdetyp som parameter skapar körningen en specialiserad allmän typ med den angivna parametern eller parametrarna som ersätts på lämpliga platser i CIL. Specialiserade generiska typer skapas en gång för varje unik värdetyp som används som en parameter.
Anta till exempel att programkoden har deklarerat en stack som är konstruerad av heltal:
Stack<int>? stack;
I det här läget genererar körningen en specialiserad version av Stack<T> klassen som har heltalet ersatt på lämpligt sätt för parametern. Nu, när programkoden använder en stack med heltal, återanvänder körningen den genererade specialiserade Stack<T> klassen. I följande exempel skapas två instanser av en stack med heltal och de delar en enda instans av Stack<int> koden:
Stack<int> stackOne = new Stack<int>();
Stack<int> stackTwo = new Stack<int>();
Anta dock att en annan Stack<T> klass med en annan värdetyp, till exempel en long eller en användardefinierad struktur som parameter, skapas vid en annan tidpunkt i koden. Som en konsekvens genererar körmiljön en annan version av den generiska typen och ersätter en long på lämpliga ställen i CIL. Konverteringar är inte längre nödvändiga eftersom varje specialiserad generisk klass internt innehåller värdetypen.
Generiska objekt fungerar något annorlunda för referenstyper. Första gången en allmän typ skapas med någon referenstyp skapar körningen en specialiserad allmän typ med objektreferenser som ersätts med parametrarna i CIL. Varje gång en konstruerad typ instansieras med en referenstyp som parameter, oavsett vilken typ den är, återanvänder körningen den tidigare skapade specialiserade versionen av den generiska typen. Detta är möjligt eftersom alla referenser har samma storlek.
Anta till exempel att du hade två referenstyper, en Customer klass och en Order klass, och anta också att du har skapat en stack med Customer typer:
class Customer { }
class Order { }
Stack<Customer> customers;
Nu genererar körningen en specialiserad version av Stack<T> klassen som lagrar objektreferenser som fylls i senare i stället för att lagra data. Anta att nästa kodrad skapar en stack av en annan referenstyp som heter Order:
Stack<Order> orders = new Stack<Order>();
Till skillnad från med värdetyper skapas inte någon annan specialiserad version av Stack<T> klassen för Order typen. I stället skapas en instans av den specialiserade versionen av Stack<T> klassen och variabeln orders är inställd på att referera till den. Anta att du sedan påträffade en kodrad för att skapa en stack av en Customer typ:
customers = new Stack<Customer>();
Precis som med den tidigare användningen av Stack<T> klassen som skapades med hjälp Order av typen skapas en annan instans av den specialiserade Stack<T> klassen. Pekarna som finns däri är inställda på att referera till ett minnesområde med storleken på en Customer typ. Eftersom antalet referenstyper kan variera kraftigt från program till program, minskar C#-implementeringen av generiska läkemedel avsevärt mängden kod genom att minska antalet specialiserade klasser som skapats av kompilatorn för generiska klasser av referenstyper.
När en allmän C#-klass instansieras med hjälp av en värdetyp eller referenstypsparameter kan reflektion köra frågor mot den vid körning och både dess faktiska typ och dess typparameter kan fastställas.