C# Genéricos Intermediário
Genéricos
Genéricos permitem escrever código reutilizável e seguro em relação a tipos, sem sacrificar desempenho. Em C#, você define classes, métodos e interfaces com parâmetros de tipo, como List<T> ou Dictionary<TKey, TValue>. O compilador gera código específico para cada tipo concreto usado, evitando boxing e casts desnecessários.
Restrições (where) limitam os tipos que podem ser usados como argumentos genéricos. Por exemplo, where T : class exige um tipo de referência, enquanto where T : IComparable<T> garante que T possa ser comparado. Isso permite chamar métodos específicos dentro do código genérico.
Covariância (out T) permite atribuir uma coleção de um tipo mais derivado a uma variável de um tipo mais base, como IEnumerable<string> para IEnumerable<object>. Contravariância (in T) faz o oposto. Esses modificadores só funcionam em interfaces e delegates.
O operador default obtém o valor padrão de um tipo: null para referências, zero para numéricos, e uma instância com campos zerados para structs. Em genéricos, default(T) é essencial para inicializar variáveis sem saber se T é classe ou struct.
Pontos-chave
- Genéricos evitam boxing e casts, melhorando desempenho e segurança de tipos.
where T : constraintrestringe os tipos aceitos e permite chamar membros específicos.- Covariância (
out) permite converterIEnumerable<Derivado>paraIEnumerable<Base>. - Contravariância (
in) permite converterIComparer<Base>paraIComparer<Derivado>. default(T)retorna o valor padrão do tipo T, útil em inicializações genéricas.
using System;
using System.Collections.Generic;
// Classe genérica com restrição: T deve ser classe e ter construtor sem parâmetros
public class Repositorio<T> where T : class, new()
{
private readonly List<T> itens = new List<T>();
public void Adicionar(T item) => itens.Add(item);
public T CriarNovo() => new T(); // possível graças à restrição new()
public void MostrarTodos()
{
foreach (var item in itens)
Console.WriteLine(item);
}
}
public class Produto
{
public string Nome { get; set; }
public override string ToString() => $"Produto: {Nome}";
}
// Método genérico com restrição a IComparable
public static class Comparador
{
public static T Max<T>(T a, T b) where T : IComparable<T>
=> a.CompareTo(b) > 0 ? a : b;
}
class Program
{
static void Main()
{
var repo = new Repositorio<Produto>();
repo.Adicionar(new Produto { Nome = "Caneta" });
repo.Adicionar(new Produto { Nome = "Caderno" });
repo.MostrarTodos();
Console.WriteLine(Comparador.Max(10, 20)); // 20
Console.WriteLine(Comparador.Max("Ana", "Bia")); // Bia
// Covariância: IEnumerable<string> para IEnumerable<object>
IEnumerable<string> strings = new List<string> { "a", "b" };
IEnumerable<object> objects = strings;
foreach (var obj in objects)
Console.WriteLine(obj);
// default(T)
T Generico<T>() => default(T);
Console.WriteLine(Generico<int>()); // 0
Console.WriteLine(Generico<string>() ?? "null"); // null
}
}