Clases genéricas (Guía de programación de C#)Generic Classes (C# Programming Guide)

Las clases genéricas encapsulan operaciones que no son específicas de un tipo de datos determinado.Generic classes encapsulate operations that are not specific to a particular data type. El uso más común de las clases genéricas es con colecciones como listas vinculadas, tablas hash, pilas, colas y árboles, entre otros.The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on. Las operaciones como la adición y eliminación de elementos de la colección se realizan básicamente de la misma manera independientemente del tipo de datos que se almacenan.Operations such as adding and removing items from the collection are performed in basically the same way regardless of the type of data being stored.

Para la mayoría de los escenarios que necesitan clases de colección, el enfoque recomendado es usar las que se proporcionan en la biblioteca de clases .NET.For most scenarios that require collection classes, the recommended approach is to use the ones provided in the .NET class library. Para más información sobre el uso de estas clases, vea Colecciones genéricas en .NET.For more information about using these classes, see Generic Collections in .NET.

Normalmente, crea clases genéricas empezando con una clase concreta existente, y cambiando tipos en parámetros de tipo de uno en uno hasta que alcanza el equilibrio óptimo de generalización y facilidad de uso.Typically, you create generic classes by starting with an existing concrete class, and changing types into type parameters one at a time until you reach the optimal balance of generalization and usability. Al crear sus propias clases genéricas, entre las consideraciones importantes se incluyen las siguientes:When creating your own generic classes, important considerations include the following:

  • Los tipos que se van a generalizar en parámetros de tipo.Which types to generalize into type parameters.

    Como norma, cuantos más tipos pueda parametrizar, más flexible y reutilizable será su código.As a rule, the more types you can parameterize, the more flexible and reusable your code becomes. En cambio, demasiada generalización puede crear código que sea difícil de leer o entender para otros desarrolladores.However, too much generalization can create code that is difficult for other developers to read or understand.

  • Las restricciones, si existen, que se van a aplicar a los parámetros de tipo (Vea Restricciones de parámetros de tipo).What constraints, if any, to apply to the type parameters (See Constraints on Type Parameters).

    Una buena norma es aplicar el máximo número de restricciones posible que todavía le permitan tratar los tipos que debe controlar.A good rule is to apply the maximum constraints possible that will still let you handle the types you must handle. Por ejemplo, si sabe que su clase genérica está diseñada para usarse solo con tipos de referencia, aplique la restricción de clase.For example, if you know that your generic class is intended for use only with reference types, apply the class constraint. Esto evitará el uso no previsto de su clase con tipos de valor, y le permitirá usar el operador as en T, y comprobar si hay valores NULL.That will prevent unintended use of your class with value types, and will enable you to use the as operator on T, and check for null values.

  • Si separar el comportamiento genérico en clases base y subclases.Whether to factor generic behavior into base classes and subclasses.

    Como las clases genéricas pueden servir como clases base, las mismas consideraciones de diseño se aplican aquí con clases no genéricas.Because generic classes can serve as base classes, the same design considerations apply here as with non-generic classes. Vea las reglas sobre cómo heredar de clases base genéricas posteriormente en este tema.See the rules about inheriting from generic base classes later in this topic.

  • Si implementar una o más interfaces genéricas.Whether to implement one or more generic interfaces.

    Por ejemplo, si está diseñando una clase que se usará para crear elementos en una colección basada en genéricos, puede que tenga que implementar una interfaz como IComparable<T> donde T es el tipo de su clase.For example, if you are designing a class that will be used to create items in a generics-based collection, you may have to implement an interface such as IComparable<T> where T is the type of your class.

Para obtener un ejemplo de una clase genérica simple, vea Introducción a los genéricos.For an example of a simple generic class, see Introduction to Generics.

Las reglas para los parámetros de tipo y las restricciones tienen varias implicaciones para el comportamiento de clase genérico, especialmente respecto a la herencia y a la accesibilidad de miembros.The rules for type parameters and constraints have several implications for generic class behavior, especially regarding inheritance and member accessibility. Antes de continuar, debe entender algunos términos.Before proceeding, you should understand some terms. Para una clase genérica Node<T>,, el código de cliente puede hacer referencia a la clase especificando un argumento de tipo, para crear un tipo construido cerrado (Node<int>).For a generic class Node<T>, client code can reference the class either by specifying a type argument, to create a closed constructed type (Node<int>). De manera alternativa, puede dejar el parámetro de tipo sin especificar, por ejemplo cuando especifica una clase base genérica, para crear un tipo construido abierto (Node<T>).Alternatively, it can leave the type parameter unspecified, for example when you specify a generic base class, to create an open constructed type (Node<T>). Las clases genéricas pueden heredar de determinadas clases base construidas abiertas o construidas cerradas:Generic classes can inherit from concrete, closed constructed, or open constructed base classes:

class BaseNode { }
class BaseNodeGeneric<T> { }

// concrete type
class NodeConcrete<T> : BaseNode { }

//closed constructed type
class NodeClosed<T> : BaseNodeGeneric<int> { }

//open constructed type
class NodeOpen<T> : BaseNodeGeneric<T> { }

Las clases no genéricas, en otras palabras, concretas, pueden heredar de clases base construidas cerradas, pero no desde clases construidas abiertas ni desde parámetros de tipo porque no hay ninguna manera en tiempo de ejecución para que el código de cliente proporcione el argumento de tipo necesario para crear instancias de la clase base.Non-generic, in other words, concrete, classes can inherit from closed constructed base classes, but not from open constructed classes or from type parameters because there is no way at run time for client code to supply the type argument required to instantiate the base class.

//No error
class Node1 : BaseNodeGeneric<int> { }

//Generates an error
//class Node2 : BaseNodeGeneric<T> {}

//Generates an error
//class Node3 : T {}

Las clases genéricas que heredan de tipos construidos abiertos deben proporcionar argumentos de tipo para cualquier parámetro de tipo de clase base que no se comparta mediante la clase heredada, como se demuestra en el código siguiente:Generic classes that inherit from open constructed types must supply type arguments for any base class type parameters that are not shared by the inheriting class, as demonstrated in the following code:

class BaseNodeMultiple<T, U> { }

//No error
class Node4<T> : BaseNodeMultiple<T, int> { }

//No error
class Node5<T, U> : BaseNodeMultiple<T, U> { }

//Generates an error
//class Node6<T> : BaseNodeMultiple<T, U> {}

Las clases genéricas que heredan de tipos construidos abiertos deben especificar restricciones que son un superconjunto de las restricciones del tipo base, o que las implican:Generic classes that inherit from open constructed types must specify constraints that are a superset of, or imply, the constraints on the base type:

class NodeItem<T> where T : System.IComparable<T>, new() { }
class SpecialNodeItem<T> : NodeItem<T> where T : System.IComparable<T>, new() { }

Los tipos genéricos pueden usar varios parámetros de tipo y restricciones, de la manera siguiente:Generic types can use multiple type parameters and constraints, as follows:

class SuperKeyType<K, V, U>
    where U : System.IComparable<U>
    where V : new()
{ }

Tipos construidos cerrados y construidos abiertos pueden usarse como parámetros de método:Open constructed and closed constructed types can be used as method parameters:

void Swap<T>(List<T> list1, List<T> list2)
{
    //code to swap items
}

void Swap(List<int> list1, List<int> list2)
{
    //code to swap items
}

Si una clase genérica implementa una interfaz, todas las instancias de esa clase se pueden convertir en esa interfaz.If a generic class implements an interface, all instances of that class can be cast to that interface.

Las clases genéricas son invariables.Generic classes are invariant. En otras palabras, si un parámetro de entrada especifica un List<BaseClass>, obtendrá un error en tiempo de compilación si intenta proporcionar un List<DerivedClass>.In other words, if an input parameter specifies a List<BaseClass>, you will get a compile-time error if you try to provide a List<DerivedClass>.

Consulte tambiénSee also