Condividi tramite


Generics nel runtime (Guida per programmatori C#)

Quando un tipo o un metodo generico viene compilato in common intermediate language (CIL), contiene metadati che lo identificano come con parametri di tipo. La modalità di utilizzo dell'CIL per un tipo generico varia a seconda che il parametro di tipo fornito sia un tipo valore o un tipo riferimento.

Quando un tipo generico viene costruito per la prima volta con un tipo di valore come parametro, il runtime crea un tipo generico specializzato con il parametro o i parametri forniti sostituiti nei punti appropriati nella CIL. I tipi generici specializzati vengono creati una volta per ogni tipo di valore univoco usato come parametro.

Si supponga, ad esempio, che il codice del programma abbia dichiarato uno stack costruito di numeri interi:

Stack<int>? stack;

A questo punto, il runtime genera una versione specializzata della Stack<T> classe con l'intero sostituito in modo appropriato per il relativo parametro. A questo punto, ogni volta che il codice del programma usa uno stack di interi, il runtime riutilizza la classe specializzata Stack<T> generata. Nell'esempio seguente vengono create due istanze di uno stack di numeri interi e condividono una singola istanza del Stack<int> codice:

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

Si supponga tuttavia che un'altra Stack<T> classe con un tipo di valore diverso, ad esempio o long una struttura definita dall'utente, venga creata in un altro punto del codice. Di conseguenza, il runtime genera un'altra versione del tipo generico e sostituisce un long nelle posizioni appropriate in CIL. Le conversioni non sono più necessarie perché ogni classe generica specializzata contiene in modo nativo il tipo di valore.

I generics funzionano in modo leggermente diverso per i tipi di riferimento. La prima volta che un tipo generico viene costruito con qualsiasi tipo riferimento, il runtime crea un tipo generico specializzato con riferimenti a oggetti sostituiti per i parametri nell'CIL. Quindi, ogni volta che viene creata un'istanza di un tipo costruito con un tipo riferimento come parametro, indipendentemente dal tipo, il runtime riutilizza la versione specializzata creata in precedenza del tipo generico. Ciò è possibile perché tutti i riferimenti hanno le stesse dimensioni.

Si supponga, ad esempio, di avere due tipi di riferimento, una Customer classe e una Order classe, e si supponga anche di aver creato uno stack di Customer tipi:

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

A questo punto, il runtime genera una versione specializzata della Stack<T> classe che archivia i riferimenti agli oggetti che verranno compilati in un secondo momento anziché archiviare i dati. Si supponga che la riga di codice successiva crei uno stack di un altro tipo di riferimento, denominato Order:

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

A differenza dei tipi valore, non viene creata un'altra versione specializzata della Stack<T> classe per il Order tipo . Viene invece creata un'istanza della versione specializzata della Stack<T> classe e la orders variabile viene impostata per farvi riferimento. Supponi di aver quindi individuato una riga di codice per creare uno stack di un Customer tipo:

customers = new Stack<Customer>();

Come per l'uso precedente della Stack<T> classe creata usando il Order tipo , viene creata un'altra istanza della classe specializzata Stack<T> . I puntatori contenuti sono impostati per fare riferimento a un'area di memoria delle dimensioni di un Customer tipo. Poiché il numero di tipi di riferimento può variare in modo selvaggio da programma a programma, l'implementazione C# di generics riduce notevolmente la quantità di codice riducendo a un numero di classi specializzate create dal compilatore per classi generiche di tipi di riferimento.

Inoltre, quando viene creata un'istanza di una classe C# generica usando un tipo di valore o un parametro di tipo riferimento, la reflection può eseguire una query in fase di esecuzione ed è possibile verificare sia il tipo effettivo che il relativo parametro di tipo.

Vedere anche