Interfaces – definir comportamento para vários tipos

Uma interface contém definições para um grupo de funcionalidades relacionadas que uma class ou um struct podem implementar. Uma interface pode definir métodos static, que devem ter uma implementação. Uma interface pode definir uma implementação padrão para membros. Uma interface pode não declarar dados de instância, como campos, propriedades implementadas automaticamente ou eventos semelhantes a propriedades.

Usando interfaces, você pode, por exemplo, incluir o comportamento de várias fontes em uma classe. Essa funcionalidade é importante em C# porque a linguagem não dá suporte a várias heranças de classes. Além disso, use uma interface se você deseja simular a herança para structs, pois eles não podem herdar de outro struct ou classe.

Você define uma interface usando a palavra-chave interface, como mostra o exemplo a seguir.

interface IEquatable<T>
{
    bool Equals(T obj);
}

O nome da interface deve ser um nome do identificador válido em C#. Por convenção, os nomes de interface começam com uma letra maiúscula I.

Qualquer classe ou struct que implemente a interface IEquatable<T> deve conter uma definição para um método Equals que corresponda à assinatura que a interface especifica. Como resultado, você pode contar com uma classe que implementa IEquatable<T> para conter um método Equals com o qual uma instância da classe pode determinar se é igual a outra instância da mesma classe.

A definição de IEquatable<T> não fornece uma implementação para Equals. Uma classe ou estrutura pode implementar várias interfaces, mas uma classe só pode herdar de uma única classe.

Para obter mais informações sobre classes abstratas, consulte Classes e membros de classes abstratos e lacrados.

As interfaces podem conter métodos, propriedades, eventos, indexadores ou qualquer combinação desses quatro tipos de membros. As interfaces podem conter construtores estáticos, campos, constantes ou operadores. A partir do C# 11, os membros da interface que não são campos podem ser static abstract. Uma interface não pode conter campos de instância, construtores de instância ou finalizadores. Os membros da interface são públicos por padrão, e você pode especificar explicitamente modificadores de acessibilidade, como public, protected, internal, private, protected internalou private protected. Um membro private deve ter uma implementação padrão.

Para implementar um membro de interface, o membro correspondente da classe de implementação deve ser público, não estático e ter o mesmo nome e assinatura do membro de interface.

Observação

Quando uma interface declara membros estáticos, um tipo que implementa essa interface também pode declarar membros estáticos com a mesma assinatura. Eles são distintos e identificados exclusivamente pelo tipo que declara o membro. O membro estático declarado em um tipo não substitui o membro estático declarado na interface.

Uma classe ou struct que implementa uma interface deve fornecer uma implementação para todos os membros declarados sem uma implementação padrão fornecida pela interface. No entanto, se uma classe base implementa uma interface, qualquer classe que é derivada da classe base herda essa implementação.

O exemplo a seguir mostra uma implementação da interface IEquatable<T>. A classe de implementação, Car, deverá fornecer uma implementação do método Equals.

public class Car : IEquatable<Car>
{
    public string? Make { get; set; }
    public string? Model { get; set; }
    public string? Year { get; set; }

    // Implementation of IEquatable<T> interface
    public bool Equals(Car? car)
    {
        return (this.Make, this.Model, this.Year) ==
            (car?.Make, car?.Model, car?.Year);
    }
}

As propriedades e os indexadores de uma classe podem definir acessadores extras para uma propriedade ou o indexador que é definido em uma interface. Por exemplo, uma interface pode declarar uma propriedade que tem um acessador get. A classe que implementa a interface pode declarar a mesma propriedade tanto com um acessador get quanto com um set. No entanto, se a propriedade ou o indexador usa a implementação explícita, os acessadores devem corresponder. Para obter mais informações sobre a implementação explícita, consulte Implementação de interface explícita e Propriedades da interface.

Uma interface pode herdar de uma ou mais interfaces. A interface derivada herda os membros de suas interfaces base. Uma classe que implementa uma interface derivada deve implementar todos os membros na interface derivada, incluindo todos os membros das interfaces base da interface derivada. Essa classe pode ser convertida implicitamente para a interface derivada ou para qualquer uma de suas interfaces base. Uma classe pode incluir uma interface várias vezes por meio das classes base que ela herda ou por meio de interfaces que outras interfaces herdam. No entanto, a classe poderá fornecer uma implementação de uma interface apenas uma vez e somente se a classe declarar a interface como parte da definição de classe (class ClassName : InterfaceName). Se a interface é herdada porque é herdada de uma classe base que implementa a interface, a classe base fornece a implementação dos membros da interface. No entanto, a classe derivada pode reimplementar qualquer membro de interface virtual em vez de usar a implementação herdada. Quando as interfaces declaram uma implementação padrão de um método, qualquer classe que implemente essa interface herda essa implementação (você precisa converter a instância da classe para o tipo de interface para acessar a implementação padrão no membro da interface).

Uma classe base também pode implementar membros de interface usando membros virtuais. Nesse caso, uma classe derivada pode alterar o comportamento da interface substituindo os membros virtuais. Para obter mais informações sobre membros virtuais, consulte Polimorfismo.

Resumo de interfaces

Uma interface tem as propriedades a seguir:

  • Nas versões do C# anteriores à 8.0, uma interface é como uma classe base abstrata que contém apenas membros abstratos. Qualquer classe ou struct que implemente uma interface deve implementar todos os seus membros.
  • A partir do C# 8.0, uma interface pode definir implementações padrão para alguns ou todos os seus membros. Uma classe ou struct que implementa a interface não precisa implementar membros que tenham implementações padrão. Para obter mais informações, consulte método de interface padrão.
  • Uma interface não pode ser instanciada diretamente. Seus membros são implementados por qualquer classe ou struct que implemente a interface.
  • Uma classe ou struct pode implementar várias interfaces. Uma classe pode herdar uma classe base e também implementar uma ou mais interfaces.