Share via


Generic Classes (C# Programming Guide)

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 a classes de coleção, a abordagem recomendada é usar os fornecidos na.Biblioteca de classes do NET Framework. Para obter mais informações sobre como usar essas classes, consulte Generics in the .NET Framework Class Library (C# Programming Guide).

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 no tipo de parâmetros.

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

  • Quais restrições, se houver, para aplicar os parâmetros de tipo (consulte Constraints on Type Parameters (C# Programming Guide)).

    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 indesejado da sua classe com os tipos de valor e permitem que você use o as o 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.

  • Se 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, talvez você precise implementar uma interface, como IComparable<T> onde T é o tipo da sua turma.

Para obter um exemplo de uma classe genérica simples, consulte Introduction to Generics (C# Programming Guide).

As regras para os parâmetros de tipo e restrições tem várias implicações para o comportamento da classe genérica, especialmente sobre a acessibilidade de herança e membro. Antes de prosseguir, você deve entender alguns termos. Para uma classe genérica Node<T>, código de 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, fechados 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 de abrir 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 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 tipos construídos construídos e fechados podem ser usados 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 para essa 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

Generics (C# Programming Guide)

System.Collections.Generic

Conceitos

C# Programming Guide

Outros recursos

Salvar o estado de enumeradores

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