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 zprostředkujícího jazyka (CIL) obsahuje metadata, která jej identifikují jako 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 hodnotou typu jako parametr vytvoří modul runtime specializovaný obecný typ s zadaným parametrem nebo parametry nahrazenými v příslušných umístěních 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. V důsledku toho modul runtime vygeneruje jinou verzi obecného typu a nahradí v příslušných umístěních v CIL jinou long verzi. 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. Pokaždé, když se vytvořený typ vytvoří instance s referenčním typem jako jeho parametrem bez ohledu na typ, který je, modul runtime znovu použije dříve 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 Order tento typ vytvořena jiná specializovaná verze Stack<T> 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 pak narazili na řádek kódu pro vytvoření zásobníku Customer typu:

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 něm obsaženy, jsou nastaveny tak, aby odkazovat na oblast paměti velikost Customer typu. 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 za běhu dotazovat a zjistit jeho skutečný typ i parametr typu.

Viz také