Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Amikor egy általános típust vagy metódust általános köztes nyelvre (CIL) fordítanak le, olyan metaadatokat tartalmaz, amelyek típusparaméterekként azonosítják. Az általános típus CIL-jének használata attól függ, hogy a megadott típusparaméter értéktípus vagy referenciatípus-e.
Amikor egy általános típust először paraméterként értéktípussal hoznak létre, a futtatókörnyezet létrehoz egy speciális általános típust a megadott paraméterrel vagy paraméterekkel a CIL megfelelő helyeiben. A speciális általános típusok minden paraméterként használt egyedi értéktípushoz egyszer jönnek létre.
Tegyük fel például, hogy a programkód egy egész számokból álló vermet deklarált:
Stack<int>? stack;
Ezen a ponton a futtatókörnyezet létrehoz egy speciális verzióját az Stack<T> osztálynak, amely az egész számot megfelelően helyettesítette a paraméterével. Most, amikor a programkód egész számokat használ, a futtatókörnyezet újra felhasználja a létrehozott specializált Stack<T> osztályt. Az alábbi példában két egész számból álló halom példánya jön létre, és a kód egyetlen példányát Stack<int> osztják meg:
Stack<int> stackOne = new Stack<int>();
Stack<int> stackTwo = new Stack<int>();
Tegyük fel azonban, hogy egy másik Stack<T> , más értéktípusú osztály, például egy felhasználó által definiált long struktúra jön létre a kód egy másik pontján. Ennek eredményeképpen a futtatókörnyezet létrehoz egy másik verzióját az általános típusnak, és a CIL megfelelő helyeiben lecserél egy long-t. A konverziókra már nincs szükség, mert minden speciális általános osztály natív módon tartalmazza az értéktípust.
A generikusok némileg eltérően működnek a referenciatípusok esetében. Amikor az első alkalommal létrehoz egy általános típust bármilyen referenciatípussal, a futtatókörnyezet létrehoz egy speciális általános típust, amely a CIL paraméterei helyett objektumhivatkozásokat tartalmaz. Ezután minden alkalommal, amikor egy létrehozott típust egy referenciatípussal példányosítanak paraméterként, a futtatókörnyezet újra felhasználja az általános típust korábban létrehozott speciális verzióját, attól függetlenül, hogy milyen típusú. Ez azért lehetséges, mert minden hivatkozás mérete megegyezik.
Tegyük fel például, hogy két referenciatípussal rendelkezik, egy Customer osztálysal és egy Order osztálysal, és azt is tegyük fel, hogy létrehozott egy típusok halomát Customer :
class Customer { }
class Order { }
Stack<Customer> customers;
Ezen a ponton a futtatókörnyezet létrehozza az osztály egy speciális verzióját, amely az Stack<T> adatok tárolása helyett később kitöltendő objektumhivatkozásokat tárol. Tegyük fel, hogy a következő kódsor létrehoz egy másik referenciatípusú halmot, amelynek neve Order:
Stack<Order> orders = new Stack<Order>();
Az értéktípusoktól eltérően az Stack<T> osztály egy másik speciális verziója nem jön létre a Order típushoz. Ehelyett létrehozzák a Stack<T> osztály specializált verziójának egy példányát, és a orders változó úgy van beállítva, hogy erre hivatkozzon. Tegyük fel, hogy ekkor egy kódsorba ütközött, amely egy típusból álló Customer vermet hoz létre:
customers = new Stack<Customer>();
A típussal Stack<T> létrehozott osztály korábbi használatához Order hasonlóan a speciális Stack<T> osztály egy másik példánya is létrejön. Az abban található mutatók egy olyan memóriaterületre vannak beállítva, amely egy Customer típus méretére mutat. Mivel a referenciatípusok száma programonként változó lehet, a generikusok C#-implementációja jelentősen csökkenti a kód mennyiségét azáltal, hogy a fordító által a referenciatípusok általános osztályaihoz létrehozott speciális osztályok számát egyre csökkenti.
Továbbá, ha egy általános C#-osztályt értéktípussal vagy referenciatípus-paraméterrel példányosít, a reflection futásidőben lekérdezheti, és megállapíthatóak mind a tényleges típusa, mind a típusparamétere.