Vantaggi dei generics (Guida per programmatori C#)

I generics rappresentano la soluzione a una limitazione presente nelle versioni precedenti di Common Language Runtime e del linguaggio C#, in cui la generalizzazione viene effettuata mediante il cast di tipi in e dal tipo base universale Object. Una classe generica consente invece di creare un insieme indipendente dai tipi in fase di compilazione.

È possibile dimostrare le limitazioni associate all'utilizzo di classi di insiemi non generiche scrivendo un breve programma in cui si utilizza la classe Collection ArrayList della libreria di classi di .NET Framework. ArrayList è una classe Collection estremamente utile che è possibile utilizzare senza modifiche per archiviare qualsiasi tipo di riferimento o di valore.

// The .NET Framework 1.1 way to create a list:
System.Collections.ArrayList list1 = new System.Collections.ArrayList();
list1.Add(3);
list1.Add(105);

System.Collections.ArrayList list2 = new System.Collections.ArrayList();
list2.Add("It is raining in Redmond.");
list2.Add("It is snowing in the mountains.");

Questa soluzione presenta tuttavia anche alcuni svantaggi. Qualsiasi tipo di riferimento o di valore aggiunto a ArrayList viene implicitamente sottoposto a upcast in Object. Se gli elementi sono tipi di valore, devono essere boxed quando vengono aggiunti all'elenco e unboxed quando vengono recuperati. Le operazioni di cast e quelle di boxing e unboxing influiscono negativamente sulle prestazioni. L'effetto delle conversioni boxing e unboxing può essere piuttosto significativo nelle situazioni in cui è necessario scorrere gli elementi di insiemi di grandi dimensioni.

L'altra limitazione è la mancanza di controllo dei tipi in fase di compilazione. Poiché ArrayList esegue il cast di tutti gli elementi in Object, non è possibile impedire situazioni simili a quella riportata di seguito nel codice client in fase di compilazione:

System.Collections.ArrayList list = new System.Collections.ArrayList();
// Add an integer to the list.
list.Add(3);
// Add a string to the list. This will compile, but may cause an error later.
list.Add("It is raining in Redmond.");

int t = 0;
// This causes an InvalidCastException to be returned.
foreach (int x in list)
{
    t += x;
}

Anche se perfettamente accettabile e a volte intenzionale se si crea un insieme eterogeneo, la combinazione di stringhe e ints in un'unica classe ArrayList si rivela nella maggior parte dei casi un errore di programmazione, che verrà rilevato solo in fase di esecuzione.

Nelle versioni 1.0 e 1.1 del linguaggio C# era possibile evitare i rischi del codice generalizzato nelle classi Collection della libreria di classi base di .NET Framework solo scrivendo insiemi specifici di tipi. Ovviamente, poiché una classe di questo tipo non è riutilizzabile per più di un tipo di dati, si perdono i vantaggi della generalizzazione ed è necessario riscrivere la classe per ogni tipo che verrà archiviato.

Per la classe ArrayList e altre classi simili è in realtà necessario specificare nel codice client, per ogni singola istanza, il particolare tipo di dati che si prevede di utilizzare. In questo modo non è più necessario eseguire l'upcast in T:System.Object ed è inoltre possibile demandare al compilatore il controllo dei tipi. In altre parole, la classe ArrayList richiede un parametro di tipo, esattamente ciò che viene fornito dai generics. Nell'insieme List<T> generico dello spazio dei nomi N:System.Collections.Generic la stessa operazione di aggiunta di elementi all'insieme è simile a quella riportata di seguito:

// The .NET Framework 2.0 way to create a list
List<int> list1 = new List<int>();

// No boxing, no casting:
list1.Add(3);

// Compile-time error:
// list1.Add("It is raining in Redmond.");

Per il codice client, l'unica sintassi aggiunta con List<T> rispetto a ArrayList è l'argomento di tipo nella dichiarazione e nella creazione di istanze. Anche se tale codifica implica una maggiore complessità, consente di creare un elenco non solo più sicuro di ArrayList, ma anche sensibilmente più veloce, soprattutto quando le voci dell'elenco sono tipi di valore.

Vedere anche

Riferimenti

Introduzione ai generics (Guida per programmatori C#)

System.Collections.Generic

Boxing e unboxing (Guida per programmatori C#)

Concetti

Guida per programmatori C#

Altre risorse

Procedure consigliate relative alle raccolte