Generics (Classes e Métodos)
Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 42 de 70.
Generics permitem que você escreva classes e métodos que funcionam com qualquer tipo de dado, mantendo a segurança de tipos. Em vez de escrever classes separadas para IntList, StringList e DoubleList, você escreve uma única classe genérica que lida com todos eles.
Uma classe genérica usa um parâmetro de tipo, tipicamente chamado T, envolto em colchetes angulares:
public class Box<T>
{
private T content;
public void Store(T item) => content = item;
public T Retrieve() => content;
}
// Uso com tipos diferentes
Box<int> intBox = new Box<int>();
intBox.Store(42);
Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");Quando você cria Box<int>, o compilador substitui cada T por int. Isso fornece verificação de tipo em tempo de compilação - você não pode armazenar acidentalmente uma string em uma caixa int.
Métodos genéricos funcionam de forma semelhante, permitindo que um único método opere em diferentes tipos:
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // x=2, y=1O compilador infere o tipo a partir dos argumentos, então você não precisa escrever Swap<int> explicitamente. Genéricos são a base de coleções como List<T> e Dictionary<TKey, TValue>, permitindo código reutilizável e com segurança de tipos.
Desafio
FácilVamos construir um sistema genérico Storage<T> que pode conter e gerenciar itens de qualquer tipo. Você criará uma classe de contêiner reutilizável que demonstra o poder dos genéricos - escreva uma vez, use com inteiros, strings ou qualquer outro tipo!
Você organizará seu código em dois arquivos:
Storage.cs: Crie uma classe genéricaStorage<T>no namespaceDataStorage. Seu contêiner de armazenamento deve:- Ter um array privado do tipo
Tpara conter os itens e uma propriedadeCountrastreando quantos itens estão armazenados - Aceitar uma capacidade em seu construtor para inicializar o array interno
- Ter um método
Add(T item)que adiciona um item se houver espaço - Ter um método
Get(int index)que retorna o item no índice especificado - Ter um método
GetAll()que retorna todos os itens armazenados unidos por", "
- Ter um array privado do tipo
Program.cs: Em seu arquivo principal, demonstre sua classe genérica funcionando com dois tipos diferentes. Crie umStorage<int>e umStorage<string>, adicione itens a cada um e mostre que a mesma classe funciona perfeitamente com ambos os tipos.
Você receberá quatro entradas:
- Primeiro inteiro para armazenar
- Segundo inteiro para armazenar
- Primeira string para armazenar
- Segunda string para armazenar
Crie um armazenamento de inteiros com capacidade 5 e um armazenamento de strings com capacidade 5. Adicione os dois inteiros ao armazenamento de inteiros e as duas strings ao armazenamento de strings.
Imprima a saída neste formato:
Int storage: {GetAll()}
Int count: {Count}
First int: {Get(0)}
String storage: {GetAll()}
String count: {Count}
First string: {Get(0)}Por exemplo, se as entradas forem 42, 100, Hello, e World, a saída deve ser:
Int storage: 42, 100
Int count: 2
First int: 42
String storage: Hello, World
String count: 2
First string: HelloObserve como você escreve a classe Storage<T> uma vez, mas ela funciona perfeitamente com int e string - essa é a mágica dos genéricos! O compilador garante a segurança de tipos, então você não pode adicionar acidentalmente uma string ao seu armazenamento de inteiros.
Folha de consulta
Generics permitem que você escreva classes e métodos que funcionam com qualquer tipo de dado, mantendo a segurança de tipos.
Uma classe genérica usa um parâmetro de tipo (geralmente T) entre colchetes angulares:
public class Box<T>
{
private T content;
public void Store(T item) => content = item;
public T Retrieve() => content;
}Ao criar uma instância, especifique o tipo para substituir T:
Box<int> intBox = new Box<int>();
intBox.Store(42);
Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");Métodos genéricos permitem que um único método opere em diferentes tipos:
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // O compilador infere o tipo a partir dos argumentosGenerics fornecem verificação de tipo em tempo de compilação e são a base de coleções como List<T> e Dictionary<TKey, TValue>.
Experimente você mesmo
using System;
using DataStorage;
class Program
{
public static void Main(string[] args)
{
// Ler as entradas
int num1 = Convert.ToInt32(Console.ReadLine());
int num2 = Convert.ToInt32(Console.ReadLine());
string str1 = Console.ReadLine();
string str2 = Console.ReadLine();
// TODO: Criar um Storage<int> com capacidade 5
// TODO: Adicionar os dois inteiros ao armazenamento de inteiros
// TODO: Criar um Storage<string> com capacidade 5
// TODO: Adicionar as duas strings ao armazenamento de strings
// TODO: Imprimir a saída no formato exigido
// Int storage: {GetAll()}
// Int count: {Count}
// First int: {Get(0)}
// String storage: {GetAll()}
// String count: {Count}
// First string: {Get(0)}
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de Métodos