Polymorphism
Como o mesmo contrato executa comportamentos diferentes em runtime via virtual dispatch, interfaces e pattern matching
Polimorfismo permite que codigo chame operacoes num tipo base enquanto executa o comportamento do tipo derivado em runtime. E o princpio que torna possivel o Open/Closed Principle (OCP) do SOLID.
O que e polimorfismo?
Polimorfismo ("muitas formas") permite que um unico contrato (classe base ou interface) tenha multiplas implementacoes. O runtime decide qual metodo executar baseado no tipo real do objeto, nao no tipo da variavel.
Formas de polimorfismo em C#
| Forma | Mecanismo | Dispatch | Quando usar |
|---|---|---|---|
| Subtyping (heranca) | virtual + override | Dinamico (runtime) | Comportamento extensivel com estado compartilhado |
| Interfaces | interface + implementacao | Dinamico (runtime) | Desacoplamento, multiplas capacidades, testabilidade |
| Abstract classes | abstract + override | Dinamico (runtime) | Template Method, forcar implementacao com base compartilhada |
| Pattern matching | switch / is | Explicito (compile-time check) | Comportamento one-off sem modificar tipos |
| Delegates | Func<T> / Action<T> | Composicao | Strategy leve, sem heranca |
| new (hiding) | new keyword | Estatico (compile-time) | Evitar β nao e polimorfismo real |
Virtual dispatch β como funciona
Quando voce declara um metodo como virtual ou abstract, o CLR cria uma virtual method table (vtable) para cada tipo. Em runtime:
- O CLR olha o tipo real do objeto (nao o tipo da variavel)
- Busca na vtable desse tipo qual metodo corresponde
- Executa o metodo da classe derivada (override)
Isso significa que Shape s = new Circle(2); s.Area(); executa Circle.Area(), mesmo que a variavel seja do tipo Shape.
Regras fundamentais
abstract
- Nao tem implementacao na classe base
- Classes derivadas devem implementar
- A classe base tambem deve ser
abstract - Nao pode ser instanciada diretamente
virtual
- Tem implementacao padrao na classe base
- Classes derivadas podem fazer override
- Se nao fizerem override, herdam o comportamento base
- A classe base pode ser concreta
sealed override
- Faz override do metodo base
- Impede que classes mais derivadas facam override novamente
- Otimizacao: o JIT pode fazer devirtualization
- Seguranca: garante comportamento final
new (hiding)
- Nao e polimorfismo β esconde o membro base
- O metodo chamado depende do tipo da variavel, nao do objeto
- Gera warning CS0108 se omitido
- Evitar em producao β causa confusao
Qual a diferenca entre virtual e abstract?
abstract nao tem corpo β forca a classe derivada a implementar. virtual tem implementacao padrao β a classe derivada pode opcionalmente fazer override. Ambos participam de virtual dispatch (polimorfismo runtime). O que acontece se eu chamar um metodo virtual no construtor da classe base?
O virtual dispatch ja esta ativo, entao o metodo da classe derivada e chamado β mas o construtor da derivada ainda nao rodou. Isso pode causar bugs porque o objeto esta em estado inconsistente. Evite chamar metodos virtuais em construtores.
Por que sealed override melhora performance?
Com
sealed override, o JIT sabe que nao existem mais overrides possiveis. Isso permite devirtualization β o JIT substitui a chamada virtual por uma chamada direta, eliminando a indirection da vtable. Em hot paths, isso pode ter impacto mensuravel.