Classi e metodi generici

Generics introduce il concetto di parametri di tipo in .NET. I generics consentono di progettare classi e metodi che rinviano la specifica di uno o più parametri di tipo fino a quando non si usa la classe o il metodo nel codice. Ad esempio, usando un parametro di tipo generico T è possibile scrivere un'unica classe che altro codice client può usare senza rischiare cast di runtime o operazioni di conversione boxing, come illustrato di seguito:

// Declare the generic class.
public class GenericList<T>
{
    public void Add(T input) { }
}
class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        // Declare a list of type int.
        GenericList<int> list1 = new GenericList<int>();
        list1.Add(1);

        // Declare a list of type string.
        GenericList<string> list2 = new GenericList<string>();
        list2.Add("");

        // Declare a list of type ExampleClass.
        GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
        list3.Add(new ExampleClass());
    }
}

Le classi e i metodi generici combinano riutilizzabilità, sicurezza dei tipi ed efficienza in modo che le controparti non generiche non possano. I parametri di tipo generico vengono sostituiti con gli argomenti di tipo durante la compilazione. Nell'esempio precedente il compilatore sostituisce T con int. I generics sono in genere usati con le raccolte e i metodi che operano su di essi. Lo spazio dei nomi System.Collections.Generic contiene diverse classi di raccolta generiche. Le raccolte non generiche, ad esempio ArrayList non sono consigliate e vengono mantenute solo a scopo di compatibilità. Per altre informazioni, vedere Generics in .NET.

È anche possibile creare tipi e metodi generici personalizzati per offrire le proprie soluzioni e schemi progettuali generalizzati che sono indipendenti dai tipi ed efficienti. Nell'esempio di codice riportato di seguito viene illustrata una classe di elenco collegato generica semplice a scopo dimostrativo. Nella maggior parte dei casi, è consigliabile usare la List<T> classe fornita da .NET anziché crearne di personalizzate. Il parametro T di tipo viene usato in diverse posizioni in cui in genere viene usato un tipo concreto per indicare il tipo dell'elemento archiviato nell'elenco:

  • Come tipo di un parametro del metodo nel metodo AddHead.
  • Come tipo restituito della proprietà Data nella classe Node annidata.
  • Come tipo del membro privato data nella classe annidata.

T è disponibile per la classe Node annidata. Quando GenericList<T> viene creata un'istanza con un tipo concreto, ad esempio come GenericList<int>, ogni occorrenza di T viene sostituita con int.

// type parameter T in angle brackets
public class GenericList<T>
{
    // The nested class is also generic on T.
    private class Node
    {
        // T used in non-generic constructor.
        public Node(T t)
        {
            next = null;
            data = t;
        }

        private Node? next;
        public Node? Next
        {
            get { return next; }
            set { next = value; }
        }

        // T as private member data type.
        private T data;

        // T as return type of property.
        public T Data
        {
            get { return data; }
            set { data = value; }
        }
    }

    private Node? head;

    // constructor
    public GenericList()
    {
        head = null;
    }

    // T as method parameter type:
    public void AddHead(T t)
    {
        Node n = new Node(t);
        n.Next = head;
        head = n;
    }

    public IEnumerator<T> GetEnumerator()
    {
        Node? current = head;

        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }
}

Nell'esempio di codice riportato di seguito viene illustrato come il codice client usa la classe generica GenericList<T> per creare un elenco di interi. Se si modifica l'argomento di tipo, il codice seguente crea elenchi di stringhe o qualsiasi altro tipo personalizzato:

class TestGenericList
{
    static void Main()
    {
        // int is the type argument
        GenericList<int> list = new GenericList<int>();

        for (int x = 0; x < 10; x++)
        {
            list.AddHead(x);
        }

        foreach (int i in list)
        {
            System.Console.Write(i + " ");
        }
        System.Console.WriteLine("\nDone");
    }
}

Nota

I tipi generici non sono limitati alle classi. Gli esempi precedenti usano class tipi, ma è possibile definire tipi e struct genericiinterface, inclusi record i tipi.

Panoramica sui generics

  • Usare i tipi generici per ottimizzare il riutilizzo del codice, l'indipendenza dai tipi e le prestazioni.
  • L'uso più comune dei generics consiste nel creare classi di raccolte.
  • La libreria di classi .NET contiene diverse classi di raccolte generiche nello spazio dei nomi System.Collections.Generic. Queste raccolte generiche devono essere usate ogni volta che sia possibile al posto di classi come ArrayList nello spazio dei nomi System.Collections.
  • È possibile creare interfacce, classi, metodi, eventi e delegati generici.
  • Le classi generiche possono essere vincolate per consentire l'accesso ai metodi in tipi di dati specifici.
  • È possibile ottenere informazioni in fase di esecuzione sui tipi usati in un tipo di dati generico tramite reflection.

Specifiche del linguaggio C#

Per altre informazioni, vedere la specifica del linguaggio C#.

Vedi anche