Capítulo 11: Herança, Polimorfismo e Default Interface Methods
Capítulo 11: Herança, Polimorfismo e Default Interface Methods
Especialização em Sistemas com C# • C# 12 & .NET 8 • POO Moderna, LINQ, Concorrência e Arquitetura Corporativa
🗺️ Mapa Conceitual de Polimorfismo e Evolução de Interfaces
flowchart TD
Abstracao["Abstração de Contratos"] --> ClassesAbstratas["Classes Abstratas (abstract class)"]
Abstracao --> Interfaces["Interfaces (interface)"]
subgraph CLASS_POLY["Polimorfismo Baseado em Classes"]
AbstractMethod["abstract: Obriga Implementação na Subclasse"]
VirtualMethod["virtual: Fornece Implementação Padrão Sobrescrevível"]
Override["override: Especializa o Método na Derivada"]
Sealed["sealed: Impede Especializações Subsequentes"]
end
subgraph INTERFACE_EVO["Evolução Moderna de Interfaces"]
DIM["Default Interface Methods (DIM - C# 8+)"]
StaticAbstract["Static Abstract Members in Interfaces (C# 11)"]
end
ClassesAbstratas --> CLASS_POLY
Interfaces --> INTERFACE_EVO
CLASS_POLY --> VTable["Despacho Dinâmico via VTable da CLR"]
INTERFACE_EVO --> GenericMath["Aritmética Genérica e Contratos Estáticos"]
style Abstracao fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style CLASS_POLY fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style INTERFACE_EVO fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
🏛️ 1. Polimorfismo na CLR: Como Funciona o Despacho Virtual
No ecossistema .NET, os métodos são não-virtuais por padrão (ao contrário de Java, onde todos os métodos públicos são virtuais). Isso significa que, a menos que você marque explicitamente um método com a palavra-chave virtual, o compilador Roslyn emite a instrução IL call, que despacha a execução diretamente para o endereço de código fixo sem consultar tabelas de métodos virtuais.
Quando um método é marcado como virtual ou abstract:
- O compilador emite a instrução IL
callvirt. - O runtime consulta a MethodTable do objeto real no Heap gerenciado para resolver dinamicamente o método sobrescrito (
override). - Uma verificação implícita de nulidade (Null Check) é executada pela CPU antes do desvio.
⚙️ 2. Bloqueio de Herança e Otimizações com sealed
Marcar uma classe ou método como sealed impede que outras classes derivem dela ou continuem a sobrescrever aquele comportamento.
O Benefício Oculto de Performance do sealed:
Além de expressar a intenção de design de que a classe está completa, o uso de sealed permite ao RyuJIT realizar Devirtualização Estática:
- Como o JIT sabe que não podem existir subclasses futuras daquela classe
sealed, ele pode transformar chamadas virtuais caras em chamadas diretas normais. - O JIT pode até mesmo aplicar inlining no corpo do método, eliminando o custo de empilhar parâmetros na chamada de função!
📦 3. Default Interface Methods (DIM): Evolução Não Destrutiva de APIs
Historicamente, adicionar um novo método a uma interface pública publicada quebrava o código de todos os clientes que a implementavam, pois eles eram forçados a implementar o novo membro imediatamente.
Com os Default Interface Methods (introduzidos no C# 8):
- Uma interface pode fornecer uma implementação padrão em seu próprio corpo.
- Classes existentes continuam compilando e funcionando normalmente.
- Classes que necessitarem de comportamento customizado podem optar por sobrescrever o método.
public interface IRepositório<T>
{
Task<T> ObterPorIdAsync(int id);
// Método com implementação padrão:
async Task<bool> ExisteAsync(int id)
{
var item = await ObterPorIdAsync(id);
return item != null;
}
}
📊 4. Matriz Comparativa: Classes Abstratas vs Interfaces Modernas
| Característica | Classe Abstrata (abstract class) |
Interface Moderna (interface) |
|---|---|---|
| Herança Múltipla | Não (apenas herança simples em C#) | Sim (uma classe implementa N interfaces) |
| Estado de Instância (Campos) | Sim (campos privados e propriedades com backing fields) | Não (apenas propriedades sem estado) |
| Construtores de Instância | Sim (inicializam a classe base) | Não |
| Métodos com Implementação | Sim (métodos concretos normais) | Sim (via Default Interface Methods) |
| Membros Estáticos Abstratos | Não | Sim (static abstract para Generic Math) |
🔬 5. Laboratório de Arquitetura: Membros Estáticos Abstratos em Interfaces (C# 11+)
Uma das adições mais sofisticadas do C# 11 é a capacidade de declarar membros static abstract em interfaces, viabilizando o projeto de Aritmética Genérica (Generic Math):
public interface IMonoid<T> where T : IMonoid<T>
{
// Obriga o tipo a fornecer um valor neutro estático e operador de adição!
static abstract T ElementoNeutro { get; }
static abstract T operator +(T esquerda, T direita);
}
// Algoritmo genérico numérico sem saber o tipo concreto em tempo de design:
public static T SomarTudo<T>(ReadOnlySpan<T> itens) where T : IMonoid<T>
{
T acumulador = T.ElementoNeutro;
foreach (var item in itens)
{
acumulador += item;
}
return acumulador;
}
Isso permitiu ao .NET padronizar interfaces numéricas como INumber<T>, permitindo escrever algoritmos matemáticos universais que operam sobre int, double, float, decimal ou tipos numéricos customizados com performance nativa.