Clases y métodos genéricos

Los genéricos presentan el concepto de parámetros de tipo en .NET. Los genéricos permiten diseñar clases y métodos que aplazan la especificación de uno o varios parámetros de tipo hasta que se usa la clase o el método en el código. Por ejemplo, al usar un parámetro de tipo genérico T, puede escribir una clase única que otro código de cliente puede usar sin incurrir en el costo o riesgo de conversiones en tiempo de ejecución u operaciones de conversión boxing, como se muestra aquí:

// 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());
    }
}

Las clases y métodos genéricos combinan reusabilidad, seguridad de tipos y eficacia de una manera en que sus homólogos no genéricos no pueden. Los parámetros de tipo genérico se reemplazan por los argumentos de tipo durante la compilación. En el ejemplo anterior, el compilador reemplaza T por int. Los genéricos se usan frecuentemente con colecciones y los métodos que funcionan en ellas. El espacio de nombres System.Collections.Generic contiene varias clases de colecciones basadas en genéricos. No se recomiendan las colecciones no genéricas, como ArrayList, y se mantienen solo por compatibilidad. Para más información, vea Elementos genéricos en .NET.

También se pueden crear tipos y métodos genéricos personalizados para proporcionar soluciones y patrones de diseño generalizados propios con seguridad de tipos y eficaces. En el ejemplo de código siguiente se muestra una clase genérica simple de lista vinculada para fines de demostración. (En la mayoría de los casos, debe usar la clase List<T> proporcionada por .NET en lugar de crear la suya propia). El parámetro de tipo T se usa en diversas ubicaciones donde normalmente se usaría un tipo concreto para indicar el tipo del elemento almacenado en la lista:

  • Como el tipo de un parámetro de método en el método AddHead.
  • Como el tipo de valor devuelto de la propiedad Data en la clase anidada Node.
  • Como el tipo de miembro privado data de la clase anidada.

T está disponible para la clase Node anidada. Cuando se crea una instancia de GenericList<T> con un tipo concreto, por ejemplo como un GenericList<int>, cada repetición de T se sustituye por 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;
        }
    }
}

En el ejemplo de código siguiente se muestra cómo el código de cliente usa la clase genérica GenericList<T> para crear una lista de enteros. Si cambia el argumento de tipo, el código siguiente crea listas de cadenas o cualquier otro tipo personalizado:

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:

Los tipos genéricos no se limitan a las clases. Los ejemplos anteriores usan tipos class, pero puede definir tipos genéricos interface y struct, incluidos los tipos record.

Introducción a los genéricos

  • Use tipos genéricos para maximizar la reutilización del código, la seguridad de tipos y el rendimiento.
  • El uso más común de los genéricos es crear clases de colección.
  • La biblioteca de clases de .NET contiene varias clases de colección genéricas en el espacio de nombres System.Collections.Generic. Las colecciones genéricas se deberían usar siempre que sea posible en lugar de clases como ArrayList en el espacio de nombres System.Collections.
  • Puede crear sus propias interfaces, clases, métodos, eventos y delegados genéricos.
  • Puede limitar las clases genéricas para habilitar el acceso a métodos en tipos de datos determinados.
  • Puede obtener información en tiempo de ejecución sobre los tipos que se usan en un tipo de datos genérico mediante la reflexión.

Especificación del lenguaje C#

Para obtener más información, consulte la Especificación del lenguaje C#.

Vea también