Generics em C#: para que servem e como usar para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

O que são Generics em C# e para que servem



Imagine que você está escrevendo um método que deve funcionar com diferentes tipos de dados: números inteiros, strings, objetos. Sem Generics (genéricos), você teria que duplicar o código para cada tipo ou usar object com posterior conversão de tipos. Ambas as abordagens levam a problemas: a primeira à redundância, a segunda a erros em tempo de execução.



Generics (tipos genéricos) são um mecanismo em C# que permite criar classes, métodos, interfaces e delegados que funcionam com qualquer tipo de dado, mantendo a tipagem forte. Em vez de escrever código para um tipo específico, você usa um parâmetro de tipo (geralmente denotado pela letra T), que é substituído pelo tipo real no momento do uso.



Principais vantagens dos Generics:



  • Segurança de tipos — o compilador verifica a correção do uso dos tipos em tempo de compilação
  • Desempenho — ausência de boxing/unboxing para tipos por valor
  • Reutilização de código — uma classe/método funciona com múltiplos tipos
  • Legibilidade — o código fica mais limpo e compreensível


O problema sem Generics: exemplo com object



Antes dos Generics, os desenvolvedores frequentemente usavam o tipo object para criar métodos genéricos. Vejamos um exemplo:



public class Stack{    private object[] _items = new object[10];    private int _count = 0;        public void Push(object item) { _items[_count++] = item; }    public object Pop() { return _items[--_count]; }        // Uso    Stack stack = new Stack();    stack.Push(123);           // Boxing de int para object    stack.Push("hello");       // Qualquer tipo pode ser adicionado    int number = (int)stack.Pop(); // Unboxing e conversão}


Os problemas são evidentes:

  • Ao extrair, é necessária uma conversão explícita de tipo
  • Você pode acidentalmente adicionar um valor de outro tipo
  • Para tipos por valor (int, double), ocorre boxing/unboxing, o que reduz o desempenho


Fundamentos do trabalho com Generics em C#



Criação de uma classe genérica



Vejamos o mesmo exemplo de pilha, mas usando Generics:



public class Stack<T>{    private T[] _items = new T[10];    private int _count = 0;        public void Push(T item) { _items[_count++] = item; }    public T Pop() { return _items[--_count]; }}

// UsoStack<int> intStack = new Stack<int>();intStack.Push(123);intStack.Push(456);int number = intStack.Pop(); // Unboxing não é necessário, o tipo é conhecido

Stack<string> stringStack = new Stack<string>();stringStack.Push("Hello");// stringStack.Push(123); // Erro de compilação! Segurança de tipos


O parâmetro <T> é especificado entre colchetes angulares. Ao criar uma instância, você especifica o tipo concreto, e o compilador gera uma versão especializada da classe para esse tipo.



Métodos genéricos



Generics funcionam não apenas com classes, mas também com métodos individuais:



public class Utils{    public static T Max<T>(T a, T b) where T : IComparable<T>    {        return a.CompareTo(b) > 0 ? a : b;    }}

// Usoint maxInt = Utils.Max(5, 10); // 10string maxStr = Utils.Max("apple", "banana"); // "banana"


Restrições (Constraints) em Generics



Às vezes é necessário restringir os tipos que podem ser usados com um genérico. Para isso, usam-se restrições (constraints) com a palavra-chave where:



// Restrição: T deve ser um tipo por referênciapublic class Repository<T> where T : class{                

Blogs

Book Recommendations