💻 Exemplos: Capítulo 12: Generics Avançados, Constraints Estritas e Variância
💻 Exemplos: Capítulo 12: Generics Avançados, Constraints Estritas e Variância
Especialização em Sistemas com C# • Demonstrações Práticas Compiláveis
🎯 Objetivo dos Exemplos
Demonstrar a metaprogramação segura com Generics em C#: restrições estritas de tipos (Generic Constraints como where T : unmanaged, class, new()), otimização em tempo de compilação sem boxing/unboxing e aplicação prática de Covariância (out) e Contravariância (in) em interfaces genéricas.
1. Código Fonte Completo (Program.cs)
/**
* @file Program.cs
* @brief Generics com constraints unmanaged/new, covariância e contravariância em C# 12.
*/
using System;
using System.Runtime.CompilerServices;
Console.WriteLine("=== CAPÍTULO 12: GENERICS AVANÇADOS E VARIÂNCIA ===");
// 1. Classe Genérica com Constraint 'unmanaged' (Sem ponteiros de GC / Blittable)
// Permite operações com tamanho em bytes exato via Unsafe.SizeOf
public class RingBufferNativo<T>(int capacidade) where T : unmanaged
{
private readonly T[] _buffer = new T[capacidade];
private int _indice;
public void Gravar(T item)
{
_buffer[_indice % _buffer.Length] = item;
_indice++;
}
public int TamanhoEmBytesTotal => _buffer.Length * Unsafe.SizeOf<T>();
public int Capacidade => _buffer.Length;
}
// 2. Interface Covariante com 'out' (Permite retornar tipos mais derivados)
public interface IProdutor<out T>
{
T Produzir();
}
// 3. Interface Contravariante com 'in' (Permite consumir tipos mais genéricos)
public interface IConsumidor<in T>
{
void Consumir(T item);
}
// Hierarquia para Teste de Variância
public class Mensagem { public string Texto { get; set; } = ""; }
public class AlertaCritico : Mensagem { public int NivelUrgencia { get; set; } }
public class ProdutorAlertas : IProdutor<AlertaCritico>
{
public AlertaCritico Produzir() => new() { Texto = "Falha no disco SAS", NivelUrgencia = 5 };
}
public class ConsumidorMensagens : IConsumidor<Mensagem>
{
public void Consumir(Mensagem item) => Console.WriteLine($"[CONSUMIDOR] Mensagem: {item.Texto}");
}
// Execução 1: RingBuffer com Tipos Unmanaged
var bufferFloats = new RingBufferNativo<float>(100);
bufferFloats.Gravar(1.23f);
bufferFloats.Gravar(4.56f);
Console.WriteLine($"RingBuffer<float> -> Capacidade: {bufferFloats.Capacidade} | Tamanho Fisico: {bufferFloats.TamanhoEmBytesTotal} bytes");
var bufferInts = new RingBufferNativo<long>(50);
Console.WriteLine($"RingBuffer<long> -> Capacidade: {bufferInts.Capacidade} | Tamanho Fisico: {bufferInts.TamanhoEmBytesTotal} bytes");
// Execução 2: Teste de Covariância (out)
// IProdutor<AlertaCritico> pode ser atribuído a IProdutor<Mensagem>!
IProdutor<Mensagem> produtorGenerico = new ProdutorAlertas();
Mensagem msg = produtorGenerico.Produzir();
Console.WriteLine($"\n[Covariância 'out'] Produzido: {msg.Texto} (Tipo real: {msg.GetType().Name})");
// Execução 3: Teste de Contravariância (in)
// IConsumidor<Mensagem> pode ser atribuído a IConsumidor<AlertaCritico>!
IConsumidor<AlertaCritico> consumidorEspecializado = new ConsumidorMensagens();
consumidorEspecializado.Consumir(new AlertaCritico { Texto = "Alta temperatura no rack 4", NivelUrgencia = 9 });
Console.WriteLine("[Contravariância 'in'] AlertaCritico consumido com sucesso por consumidor de Mensagem base.");
2. Instruções de Compilação e Execução
dotnet new console -n AppGenerics -f net8.0
cd AppGenerics
dotnet run
3. Saída Esperada no Terminal
=== CAPÍTULO 12: GENERICS AVANÇADOS E VARIÂNCIA ===
RingBuffer<float> -> Capacidade: 100 | Tamanho Fisico: 400 bytes
RingBuffer<long> -> Capacidade: 50 | Tamanho Fisico: 400 bytes
[Covariância 'out'] Produzido: Falha no disco SAS (Tipo real: AlertaCritico)
[CONSUMIDOR] Mensagem: Alta temperatura no rack 4
[Contravariância 'in'] AlertaCritico consumido com sucesso por consumidor de Mensagem base.