Sdílet prostřednictvím


Obecné typy v modulu runtime (průvodce programováním v C#)

Při kompilaci obecného typu nebo metody do společného mezijazyka (CIL) obsahuje metadata, která jej identifikují jako mající parametry typu. Způsob použití souboru CIL pro obecný typ závisí na tom, zda zadaný parametr typu je typ hodnoty nebo referenční typ.

Při prvním vytvoření obecného typu s hodnotovým typem jako parametrem vytvoří runtime specializovaný obecný typ se zadaným parametrem nebo parametry nahrazenými na odpovídajících místech v CIL. Specializované obecné typy se vytvářejí jednou pro každý jedinečný typ hodnoty, který se používá jako parametr.

Předpokládejme například, že kód programu deklaroval zásobník vytvořený z celých čísel:

Stack<int>? stack;

V tomto okamžiku modul runtime vygeneruje specializovanou verzi Stack<T> třídy, která má celé číslo nahrazeno odpovídajícím způsobem pro jeho parametr. Kdykoli teď kód programu používá zásobník celých čísel, modul runtime znovu použije vygenerovanou specializovanou Stack<T> třídu. V následujícím příkladu se vytvoří dvě instance zásobníku celých čísel a sdílejí jednu instanci Stack<int> kódu:

Stack<int> stackOne = new Stack<int>();
Stack<int> stackTwo = new Stack<int>();

Předpokládejme však, že jiná Stack<T> třída s jiným typem hodnoty, jako long je struktura definovaná uživatelem, jako je její parametr, je vytvořena v jiném bodě v kódu. Díky tomu modul runtime vygeneruje jinou verzi obecného typu a nahrazuje long na příslušných místech v CIL. Převody už nejsou nutné, protože každá specializovaná obecná třída nativně obsahuje typ hodnoty.

Obecné typy fungují pro odkazové typy poněkud jinak. Při prvním vytvoření obecného typu s libovolným referenčním typem modul runtime vytvoří specializovaný obecný typ s odkazy na objekty nahrazené parametry v CIL. Kdykoli je instancován vytvořený typ s referenčním typem jako jeho parametrem, bez ohledu na typ, který se použije, modul runtime znovu použije předtím vytvořenou specializovanou verzi obecného typu. To je možné, protože všechny odkazy mají stejnou velikost.

Předpokládejme například, že máte dva odkazové typy, Customer třídu a Order třídu a také předpokládejme, že jste vytvořili zásobník typů Customer :

class Customer { }
class Order { }
Stack<Customer> customers;

V tomto okamžiku modul runtime generuje specializovanou verzi Stack<T> třídy, která ukládá odkazy na objekty, které budou vyplněny později místo ukládání dat. Předpokládejme, že další řádek kódu vytvoří zásobník jiného typu odkazu, který má název Order:

Stack<Order> orders = new Stack<Order>();

Na rozdíl od typů hodnot není pro Stack<T> tento typ vytvořena jiná specializovaná verze Order třídy. Místo toho je vytvořena instance specializované verze Stack<T> třídy a orders proměnná je nastavena tak, aby odkazovala. Předpokládejme, že jste poté narazili na řádek kódu pro vytvoření zásobníku typu Customer.

customers = new Stack<Customer>();

Stejně jako u předchozího použití Stack<T> třídy vytvořené pomocí Order typu je vytvořena další instance specializované Stack<T> třídy. Ukazatele, které jsou v této struktuře obsaženy, jsou nastaveny tak, aby odkazovaly na oblast paměti typu Customer. Vzhledem k tomu, že počet referenčních typů se může výrazně lišit od programu po program, implementace obecných typů jazyka C# výrazně snižuje množství kódu snížením na jeden počet specializovaných tříd vytvořených kompilátorem pro obecné třídy odkazových typů.

Kromě toho, když se vytvoří instance obecné třídy jazyka C# pomocí parametru typu hodnoty nebo referenčního typu, reflexe ji může dotazovat za běhu a zjistit jejich skutečný typ i parametr typu.

Viz také