English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Genericidade é uma forma geral, não uma forma específica. Em C#, genérico significa não específico para um tipo de dados específico.
C# permite que você use parâmetros de tipo sem especificar um tipo de dados específico para definir classes genéricas, interfaces, classes abstratas, campos, métodos, métodos estáticos, propriedades, eventos, delegações e operadores. O parâmetro de tipo é um marcador de posição para um tipo específico que é especificado ao criar uma instância do tipo genérico.
Genericidade é declarada especificando o parâmetro de tipo em chaves angulares após o nome do tipo, por exemplo, TypeName<T>, onde T é o parâmetro de tipo.
Classe genérica é definida usando parâmetros de tipo em chaves angulares após o nome da classe. Abaixo está definida uma classe genérica.
class DataStore<T> { public T Data { get; set; } }
Acima, DataStore é uma classe genérica. T é chamado de parâmetro de tipo e pode ser usado como campo, propriedade, parâmetro de método, tipo de retorno e tipo de delegação da classe DataStore. Por exemplo, Data é uma propriedade genérica, pois usamos o parâmetro de tipo T como seu tipo, em vez de um tipo de dados específico.
Você também pode definir múltiplos parâmetros de tipo e separá-los por vírgula.
class KeyValuePair<TKey, TValue> { public TKey Key { get; set; } public TValue Value { get; set; } }
Você pode criar instâncias de classes genéricas especificando o tipo real entre chaves. Abaixo, cria-se a instância da classe genérica DataStore.
DataStore<string> store = new DataStore<string>();
Acima, especificamos o tipo string entre chaves no momento da criação da instância. Portanto, T será substituído pelo tipo T qualquer no momento da compilação, que é usado em toda a classe. Portanto, o tipo da propriedade Data é string.
A figura a seguir ilustra como funcionam os generics.
Você pode atribuir um valor de string à propriedade Data. Tentar atribuir outro valor além da string causará um erro de compilação.
DataStore<string> store = new DataStore<string>(); store.Data = "Hello World!";//obj.Data = 123; //Erro de compilação
Você pode especificar diferentes tipos de dados para diferentes objetos, conforme mostrado a seguir.
DataStore<string> strStore = new DataStore<string>(); strStore.Data = "Hello World!"; //strStore.Data = 123; // Erro de compilação DataStore<int> intStore = new DataStore<int>(); intStore.Data = 100; //intStore.Data = "Hello World!"; // Erro de compilação KeyValuePair<int, string> kvp1 = new KeyValuePair<int, string>(); kvp1.Key = 100; kvp1.Value = "Hundred"; KeyValuePair<string, string> kvp2 = new KeyValuePair<string, string>(); kvp2.Key = "IT"; kvp2.Value = "Information Technology";
As classes genéricas aumentam a reutilização. Quanto mais tipos, maior a reutilização. No entanto, uma quantidade excessiva de generalização pode tornar o código difícil de entender e manter.
As classes genéricas podem ser a base de outras classes genéricas ou não genéricas ou classes abstratas.
As classes genéricas podem derivar de outras interfaces genéricas ou não genéricas, classes ou classes abstratas.
As classes genéricas podem conter campos genéricos, mas não podem ser inicializadas.
class DataStore<T> { public T data; }
A seguir, declara um array de generics.
class DataStore<T> { public T[] data = new T[10]; }
Os métodos que declaram seus tipos de retorno ou parâmetros usando parâmetros de tipo são chamados de métodos genéricos.
class DataStore<T> { private T[] _data = new T[10]; public void AddOrUpdate(int index, T item) { if(index >= 0 && index < 10) _data[index] = item; } public T GetData(int index) { if(index >= 0 && index < 10) return _data[index]; else return default(T); } }
Os métodos AddorUpdate() e GetData() são métodos genéricos. O tipo real do parâmetro item será especificado na instância da classe DataStore<T> conforme mostrado a seguir.
DataStore<string> cities = new DataStore<string>(); cities.AddOrUpdate(0, "Mumbai"); cities.AddOrUpdate(1, "Chicago"); cities.AddOrUpdate(2, "London"); DataStore<int> empIds = new DataStore<int>(); empIds.AddOrUpdate(0, 50); empIds.AddOrUpdate(1, 65); empIds.AddOrUpdate(2, 89);
Os parâmetros de tipo genéricos podem ser usados com múltiplos parâmetros com ou sem parâmetros não genéricos e tipos de retorno. Abaixo estão exemplos válidos de sobrecarga de métodos genéricos.
public void AddOrUpdate(int index, T data) { } public void AddOrUpdate(T data1, T data2) { } public void AddOrUpdate<U>(T data1, U data2) { } public void AddOrUpdate(T data) { }
Ao usar o nome do método entre chaves angulares para especificar o parâmetro de tipo, classes não genéricas podem conter métodos genéricos, conforme mostrado a seguir.
class Printer { public void Print<T>(T data) { Console.WriteLine(data); } } Printer printer = new Printer(); printer.Print<int>(100); printer.Print(200); // Infere valores com base no especificado printer.Print<string>("Hello"); printer.Print("World!"); // Infere valores com base no especificado
Os genéricos aumentam a reutilização do código. Você não precisa escrever código para lidar com diferentes tipos de dados.
Os genéricos são seguros em termos de tipo. Se tentar usar um tipo de dados diferente do especificado na definição, ocorrerá um erro de tempo de compilação.
Os genéricos têm vantagens de desempenho, pois eliminam a possibilidade de empacotamento e desempacotamento.