Classes genéricas (Guia de Programação em C#)Generic Classes (C# Programming Guide)

As classes genéricas encapsulam operações que não são específicas de um determinado tipo de dados.Generic classes encapsulate operations that are not specific to a particular data type. O uso mais comum das classes genéricas é com coleções, como listas vinculadas, tabelas de hash, pilhas, filas, árvores e assim por diante.The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on. As operações como adicionar e remover itens da coleção são realizadas basicamente da mesma maneira, independentemente do tipo de dados que estão sendo armazenados.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.

Na maioria dos cenários que exigem classes de coleção, a abordagem recomendada é usar as que são fornecidas na biblioteca de classes do .NET.For most scenarios that require collection classes, the recommended approach is to use the ones provided in the .NET class library. Para obter mais informações sobre o uso dessas classes, consulte Coleções genéricas no .NET.For more information about using these classes, see Generic Collections in .NET.

Em geral, você cria classes genéricas iniciando com uma classe concreta existente e alterando os tipos para parâmetros de tipo, um por vez, até alcançar o equilíbrio ideal de generalização e usabilidade.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. Ao criar suas próprias classes genéricas, observe as seguintes considerações importantes:When creating your own generic classes, important considerations include the following:

  • Quais tipos generalizar em parâmetros de tipo.Which types to generalize into type parameters.

    Como uma regra, quanto mais tipos você puder parametrizar, mais flexível e reutilizável seu código se tornará.As a rule, the more types you can parameterize, the more flexible and reusable your code becomes. No entanto, generalização em excesso poderá criar um código que seja difícil de ser lido ou entendido por outros desenvolvedores.However, too much generalization can create code that is difficult for other developers to read or understand.

  • Quais restrições, se houver, aplicar aos parâmetros de tipo (consulte Restrições a parâmetros de tipo).What constraints, if any, to apply to the type parameters (See Constraints on Type Parameters).

    Uma boa regra é aplicar o máximo de restrições, de maneira que ainda seja possível manipular os tipos que você precisa manipular.A good rule is to apply the maximum constraints possible that will still let you handle the types you must handle. Por exemplo, se você souber que a classe genérica é destinada a ser usada apenas com tipos de referência, aplique a restrição da classe.For example, if you know that your generic class is intended for use only with reference types, apply the class constraint. Isso impedirá o uso não intencional de sua classe com tipos de valor e permitirá que você use o operador as em T e verificar se há valores nulos.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.

  • Se deve-se levar em consideração o comportamento genérico em subclasses e classes base.Whether to factor generic behavior into base classes and subclasses.

    Como as classes genéricas podem servir como classes base, as mesmas considerações de design aplicam-se nesse caso, como com as classes não genéricas.Because generic classes can serve as base classes, the same design considerations apply here as with non-generic classes. Consulte as regras sobre heranças de classes base genéricas mais adiante neste tópico.See the rules about inheriting from generic base classes later in this topic.

  • Se implementar uma ou mais interfaces genéricas.Whether to implement one or more generic interfaces.

    Por exemplo, se você estiver projetando uma classe que será usada para criar itens em uma coleção com base em classes genéricas, poderá ser necessário implementar uma interface como a IComparable<T>, em que T é o tipo de sua classe.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 obter um exemplo de uma classe genérica simples, consulte Introdução aos genéricos.For an example of a simple generic class, see Introduction to Generics.

As regras para parâmetros de tipo e restrições têm várias implicações para o comportamento de classes genéricas, especialmente em relação à acessibilidade de membro e herança.The rules for type parameters and constraints have several implications for generic class behavior, especially regarding inheritance and member accessibility. Antes de prosseguir, você deve compreender alguns termos.Before proceeding, you should understand some terms. Para uma classe genérica Node<T>,, o código cliente pode fazer referência à classe, especificando um argumento de tipo para criar um tipo construído fechado (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>). Como alternativa, ele pode deixar o parâmetro de tipo não especificado para criar um tipo construído aberto (Node<T>), como ao especificar uma classe base genérica.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>). As classes genéricas podem herdar de classes base construídas concretas, fechadas ou abertas: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> { }

As classes não genéricas ou em outras palavras, classes concretas, podem herdar de classes base construídas fechadas, mas não de classes construídas abertas ou de parâmetros de tipo, porque não há maneiras de o código cliente fornecer o argumento de tipo necessário para instanciar a classe base em tempo de execução.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 {}

As classes genéricas que herdam de tipos construídos abertos devem fornecer argumentos de tipo para qualquer parâmetro de tipo de classe base que não é compartilhado pela classe herdeira, conforme demonstrado no código a seguir: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> {} 

As classes genéricas que herdam de tipos construídos abertos devem especificar restrições que são um superconjunto ou sugerem, as restrições no tipo base: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() { }

Os tipos genéricos podem usar vários parâmetros de tipo e restrições, da seguinte maneira: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 construídos abertos e construídos fechados podem ser usados 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
}

Se uma classe genérica implementa uma interface, todas as instâncias dessa classe podem ser convertidas nessa interface.If a generic class implements an interface, all instances of that class can be cast to that interface.

As classes genéricas são invariáveis.Generic classes are invariant. Em outras palavras, se um parâmetro de entrada especifica um List<BaseClass>, você receberá um erro em tempo de compilação se tentar fornecer um 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 tambémSee Also