CodeGym /Cursos /C# SELF /Métodos Default de Interface

Métodos Default de Interface

C# SELF
Nível 24, Lição 0
Disponível

1. Do "contrato puro" pra arquitetura flexível

Antes do C# 8, interface era tipo contrato rígido: quer implementar a interface? Tem que implementar tudo, até o último detalhe. Se aparecia um membro novo, todas as implementações existentes tinham que adicionar rapidinho, senão o compilador nem deixava compilar o projeto.

Mas a vida é mais complicada. Imagina que você mantém uma biblioteca usada por centenas de projetos, e de repente precisa adicionar um método novo na interface. Não quer quebrar compatibilidade retroativa? É aí que entram os métodos default (Default Interface Methods, DIM)!

Qual é a ideia?

Métodos default permitem declarar a implementação do método direto na interface. Agora o contrato fica mais flex: se a classe não implementar a "novidade", vai usar a implementação default. Tipo dublê de filme: se o ator não quer pular da ponte, entra o dublê.

2. Sintaxe dos Default Interface Methods

Como declarar métodos com implementação na interface?

É bem parecido com métodos normais, só que agora o corpo do método pode (e deve) ser escrito direto na interface:


public interface ILogger
{
    void Log(string message);

    // Novo método com implementação default!
    void LogWarning(string message)
    {
        Log("[WARNING] " + message);
    }
}

Aqui o LogWarning já tem implementação! Qualquer classe que implementar ILogger só precisa implementar Log, e LogWarning vai usar a versão default (a não ser que tenha uma própria).

Compare: assinatura clássica vs. moderna

Versão Declaração na interface
Antes do C# 8
void DoSomething();
C# 8 e mais recente
void DoSomething() { Console.WriteLine("Trabalhando!"); }

Detalhes importantes da sintaxe

  • Pra método com implementação, sempre escreva o corpo do método entre chaves.
  • Métodos default não podem ser abstract.
  • Todos os métodos de interface continuam implicitamente public.
  • Dá pra declarar propriedades com get/set default também (veja abaixo).

3. Exemplos práticos

Exemplo 1. Garantindo compatibilidade retroativa

Digamos que seu app tem uma interface pra salvar dados:


public interface ISaveable
{
    void Save(string filePath);
}

Depois você decide adicionar salvar na nuvem. Não quer mexer em cem classes? Adiciona um método default!


public interface ISaveable
{
    void Save(string filePath);

    // Novo método com implementação "default"!
    void SaveToCloud(string cloudService)
    {
        Console.WriteLine($"Salvando na nuvem {cloudService} (por padrão — não faz nada)");
    }
}

Agora todas as classes antigas "sabem" salvar na nuvem (mesmo que só mostrem uma mensagem por enquanto).

Exemplo 2. Expandindo a interface do logger

Antes a gente tinha uma interface simples de logging:


public interface ILogger
{
    void Log(string message);
}

Vamos adicionar um método default pra logar erros:


public interface ILogger
{
    void Log(string message);

    void LogError(string message)
    {
        Log("[ERROR] " + message);
    }
}

A classe que implementa ILogger não precisa implementar LogError — vai funcionar a versão default:


public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
    // Não implementa LogError — vai usar a default!
}

ILogger logger = new ConsoleLogger();
logger.Log("Tudo certo!");
logger.LogError("Eita, deu ruim!"); // Vai chamar a implementação default

Exemplo 3. Métodos default + app extensível

Seu app suporta vários tipos de exportação: pra arquivo, banco de dados, rede. Interface:


public interface IExporter
{
    void Export(string data, string destination);

    // Nova funcionalidade — exportar pra arquivo zipado
    void ExportToArchive(string data, string archivePath)
    {
        Console.WriteLine("Exportar pra arquivo zip não é suportado por padrão.");
    }
}

Plugins feitos por outros devs continuam funcionando, mesmo sem saber do método novo.

4. Como funciona a chamada de métodos default da interface?

Cenário "classe antiga — interface nova"

Se a classe não implementa o método default da interface, quando chamar pelo ponteiro da interface, vai usar a implementação da interface. Se implementar — usa a dela.


public class FileExporter : IExporter
{
    public void Export(string data, string destination)
    {
        Console.WriteLine("Salvando em arquivo...");
    }
    // Não implementa ExportToArchive — vai usar a default
}

IExporter exporter = new FileExporter();
exporter.Export("dados", "file.txt");        // Chama implementação do FileExporter
exporter.ExportToArchive("dados", "file.zip"); // Chama implementação default!

Cenário "classe sobrescreve método default"


public class AdvancedExporter : IExporter
{
    public void Export(string data, string destination)
    {
        Console.WriteLine("Salvando no modo avançado...");
    }

    public void ExportToArchive(string data, string archivePath)
    {
        Console.WriteLine("Exportação zipada suportada!");
    }
}

IExporter exporter = new AdvancedExporter();
exporter.ExportToArchive("dados", "file.zip"); // Agora chama a implementação da classe!

5. O que mais dá pra fazer com Default Interface Methods?

Propriedades e eventos default

Dá pra declarar propriedades com implementação default, se tiver corpo no get ou set:


public interface IHasId
{
    // Retorna 42 automaticamente, até ser sobrescrito
    int Id => 42;
}

public class Person : IHasId {}
Console.WriteLine(new Person().Id); // 42

Chamar métodos default de dentro da interface

Dentro da interface, métodos default e outros membros podem chamar uns aos outros:


public interface IDemo
{
    void Foo() => Bar();
    void Bar() => Console.WriteLine("BAR");
}

6. Limitações e particularidades dos Default Interface Methods

Dá pra declarar campos, construtores?

Não rola. Mesmo com métodos default, interface ainda não é classe. Não pode ter campos, construtores, destrutores.

Dá pra usar base na interface?

Dá, mas tem uns detalhes. Dentro do método default da interface, dá pra chamar método da interface base usando chamada explícita:


public interface IBase
{
    void Greet() => Console.WriteLine("Hello from IBase");
}

public interface IDerived : IBase
{
    void IBase.Greet()
    {
        Console.WriteLine("Oi do IDerived!");
        IBase.Greet(this); // Chama método da interface base explicitamente
    }
}

Mas isso é raro pra cenários básicos.

O que acontece se tiver conflito de implementação default?


public interface IA { void Foo() { Console.WriteLine("A"); } }
public interface IB { void Foo() { Console.WriteLine("B"); } }

// Classe não implementa Foo explicitamente:
public class C : IA, IB { }
// Erro de compilação: não dá pra saber qual implementação usar!

7. Erros comuns, limitações e particularidades

Erro típico engraçado:
Tem gente que tenta declarar campos na interface depois de conhecer DIM — mas ainda não pode. Também, se tentar implementar método estático default — até o C# 8 não rola. (A partir do 8 já dá pra ter métodos estáticos em interface, mas implementação default pra estáticos é outro papo.)

Particularidade: Diamond Problem ("problema do losango")
Se sua classe implementa duas interfaces com o mesmo método default, você é obrigado a implementar esse método explicitamente:


public class ConflictClass : IA, IB
{
    public void Foo() // tem que escolher qual versão!
    {
        // Chama a implementação certa via interface (se quiser)
        ((IA)this).Foo();
        // ou
        ((IB)this).Foo();
    }
}

Não abuse!
Métodos default salvam a compatibilidade retroativa, mas se exagerar, sua arquitetura pode ficar "bagunçada", com lógica espalhada nas interfaces. Tenta deixar o que é importante nas classes, e usar interface só como "contrato" mesmo.

2
Tarefa
C# SELF, nível 24, lição 0
Bloqueado
Extensão de interface com método padrão
Extensão de interface com método padrão
2
Tarefa
C# SELF, nível 24, lição 0
Bloqueado
Conflito de interfaces e escolha de implementação
Conflito de interfaces e escolha de implementação
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION