Classes genéricas (guia de programação do C#)

Classes genéricas encapsulam as operações que não são específicas para um tipo de dados específico.O uso mais comum para classes genéricas é com coleções como listas vinculadas, tabelas de hash, pilhas, filas, árvores e assim por diante.Operações como, por exemplo, adicionando e removendo itens da coleção são executadas basicamente da mesma maneira independentemente do tipo de dados armazenados.

Para a maioria dos cenários que exigem as coleções de classes, a abordagem recomendada é usar os fornecidos na.Biblioteca de classes.Para obter mais informações sobre como usar essas classes, consulte Os genéricos do.NET Framework Class Library (guia de programação do C#).

Normalmente, você deve criar classes genéricas começando com uma classe concreta existente e, em seguida, alterando os tipos em parâmetros de tipo um por vez até atingir o equilíbrio ideal de generalização e usabilidade.Ao criar suas próprias classes genéricas, considerações importantes incluem o seguinte:

  • Quais tipos de generalizar em parâmetros de tipo.

    Como uma regra, quanto mais você pode parametrizar tipos, o mais flexíveis e reutilizáveis se torna seu código.No entanto, há muita generalização pode criar código que é difícil para outros desenvolvedores ler ou compreender.

  • Que restrições, se houver, para aplicar os parâmetros de tipo (consulte Restrições em parâmetros de tipo (guia de programação do C#)).

    Uma boa regra é aplicar restrições máxima possíveis que permitirá ainda que lidam com os tipos que você deve tratar.Por exemplo, se você souber que sua classe genérica é destinado ao uso somente com os tipos de referência, aplica a restrição de classe.Que impedirá o uso não intencional de sua classe com os tipos de valor e permitirá que você use o as operador em Te verifique se há valores nulos.

  • Se fator comportamento genérico em subclasses e classes base.

    Porque classes genéricas podem servir como classes base, as mesmas considerações de design se aplicam aqui como ocorre com as classes não-genéricas.Consulte as regras sobre a herança de classes genéricas de base neste tópico.

  • Decida se deseja implementar uma ou mais interfaces genéricas.

    Por exemplo, se você estiver criando uma classe que será usada para criar itens em uma coleção baseado em genéricos, você pode ter que implementar uma interface, como IComparable<T> onde T é o tipo de sua classe.

Para obter um exemplo de uma classe genérica simples, consulte Introdução aos genéricos (guia de programação do C#).

As regras para parâmetros de tipo e restrições tem várias implicações para o comportamento da classe genérica, especialmente com relação de herança e membro de acessibilidade.Antes de prosseguir, você deve entender alguns termos.Para uma classe genérica Node<T>, código do cliente pode referenciar a classe ou especificando um argumento de tipo, para criar um tipo construído fechado (Node<int>).Como alternativa, ele pode deixar o parâmetro de tipo não for especificado, por exemplo, quando você especifica uma classe genérica de base criar uma abertura construído tipo (Node<T>).Classes genéricas podem herdar de concretos, fechadas construídos ou abrir construídos classes base:

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> { }

Não genérico, em outras palavras, as classes concretas, pode herdar de classes base construídos fechadas, mas não a partir de classes construídos abertos ou parâmetros de tipo porque não há nenhuma maneira em tempo de execução de código do cliente fornecer o argumento do tipo necessário para instanciar a classe base.

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

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

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

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 herdando, conforme demonstrado no código a seguir:

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> {} 

Classes genéricas que herdam de tipos construídos abertos devem especificar restrições que são um superconjunto de ou implica, as restrições no tipo base:

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

Tipos genéricos podem usar vários parâmetros de tipo e restrições, da seguinte maneira:

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

Abrir tipo construído construído e fechado pode ser usado como parâmetros do método:

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 em interface.

Classes genéricas são invariável.Em outras palavras, se um parâmetro de entrada especifica um List<BaseClass>, você obterá um erro de tempo de compilação se você tentar fornecer um List<DerivedClass>.

Consulte também

Referência

Genéricos (guia de programação do C#)

System.Collections.Generic

Conceitos

Guia de programação do C#

Outros recursos

Salvar o estado de enumeradores

Um quebra-cabeça da herança, parte 1