Por que as interfaces C # não podem conter campos?

223

Por exemplo, suponha que eu queira uma ICarinterface e que todas as implementações contenham o campo Year. Isso significa que toda implementação deve declarar separadamente Year? Não seria melhor simplesmente definir isso na interface?

deltanovember
fonte
21
Interfaces não tem aplicação, para este uso uma classe abstrata, com a propriedade Ano
carteiro
6
Para acrescentar ao que foi dito aqui, interfaces são contratos e um campo é um detalhe de implementação, pois define um slot na memória da máquina para inserir um valor (escalar ou apontador de endereço).
precisa saber é o seguinte
5
Mas se o campo é público, faz parte do contrato e não apenas um detalhe de implementação, certo?
Alex

Respostas:

238

Embora muitas das outras respostas estejam corretas no nível semântico, acho interessante também abordar esses tipos de perguntas a partir do nível de detalhes da implementação.

Uma interface pode ser pensada como uma coleção de slots , que contêm métodos . Quando uma classe implementa uma interface, a classe é obrigada a informar ao tempo de execução como preencher todos os slots necessários. Quando voce diz

interface IFoo { void M(); } 
class Foo : IFoo { public void M() { ... } }

a classe diz "quando você criar uma instância minha, coloque uma referência ao Foo.M no slot do IFoo.M.

Então, quando você faz uma chamada:

IFoo ifoo = new Foo();
ifoo.M();

o compilador gera código que diz "pergunte ao objeto qual método está no slot para IFoo.M e chame esse método.

Se uma interface é uma coleção de slots que contêm métodos, alguns desses slots também podem conter os métodos get e set de uma propriedade, os métodos get e set de um indexador e os métodos add e remove de um evento. Mas um campo não é um método . Não há "slot" associado a um campo que você pode "preencher" com uma referência ao local do campo. E, portanto, as interfaces podem definir métodos, propriedades, indexadores e eventos, mas não campos.

Eric Lippert
fonte
26
A única coisa que às vezes sinto falta é uma capacidade semelhante a java para definir constantes no nível da interface, que presumivelmente não exigiriam um "slot" para suportar no idioma.
LBushkin
2
Eu gosto da explicação em palavras simples. Obrigado. "CLR via C #" e "Essential .net volume 1" fornecem mais detalhes.
quer
6
Por que um campo não possui um slot? e mesma pergunta com os operadores? Lembro-me de ouvir sobre digitação de pato usando reflexão para ver se uma interface é implementada, mesmo se a classe não herdou a interface. Por que a reflexão não pode (ou um slot) ser usada para abrir um campo? Ainda estou escrevendo meu código, por isso talvez não precise / queira campos, mas fiquei surpreso ao descobrir que não posso usar operadores. operadores são exatamente como os métodos de meu entendimento, exceto nem todos podem ser sobrecarregados ( An interface cannot contain constants, fields, operatorsDo. msdn.microsoft.com/en-us/library/ms173156.aspx )
@acidzombie: A questão de por que uma interface não pode definir operadores é diferente (embora talvez relacionada) do por que não pode conter campos; Sugiro postar outra pergunta se você ainda estiver interessado nisso.
Adam Robinson
1
@ b1nary.atr0phy por que com campos? Por exemplo, se eu declarei um método int One(), a implementação public int One(){return 1;}não é um campo.
Hi-Angel
131

As interfaces em C # destinam-se a definir o contrato ao qual uma classe cumprirá - e não uma implementação específica.

Nesse sentido, as interfaces C # permitem definir propriedades - para as quais o responsável pela chamada deve fornecer uma implementação:

interface ICar
{
    int Year { get; set; }
}

As classes de implementação podem usar propriedades automáticas para simplificar a implementação, se não houver uma lógica especial associada à propriedade:

class Automobile : ICar
{
    public int Year { get; set; } // automatically implemented
}
LBushkin
fonte
5
Tudo o que não é público faz parte do contrato. Se uma classe tem public int Year, não diz que o contrato da classe tem um campo do tipo Year para estar presente e acessível?
Didier A.
1
Atrasado para a parte, mas não, neste caso, significa que o contrato tem um ano de PROPRIEDADE que qualquer classe permanente deve implementar. Na verdade, as propriedades são métodos get / set, que têm o campo de apoio gerado automaticamente se nenhuma lógica especial for necessária. Sintaxe especial é apenas para uma notação mais clara.
user3613916
Como posso definir um valor padrão constante (como 123) para a implementação automática de Year?
Lama12345
1
@ lama12345 Também estou atrasado para a festa, mas desde o C # 6 (2015, .NET Framework 4.6 e .NET Core) você pode usar uma propriedade automática para esse fim. public int Year => 123;. No entanto, neste caso, não faz sentido ter um setter, portanto a interface teria que ser definida comint Year { get; }
EriF89
56

Declare-o como uma propriedade:

interface ICar {
   int Year { get; set; }
}
Tarydon
fonte
47
A pergunta é " Por que as interfaces C # não podem conter campos?". Isso não resolve isso.
precisa saber é o seguinte
14
Concordo que a resposta desta resposta não responde à pergunta do OP, mas bem, resolveu o meu problema.
Gorgen
36

Eric Lippert acertou em cheio, vou usar uma maneira diferente de dizer o que ele disse. Todos os membros de uma interface são virtuais e todos precisam ser substituídos por uma classe que herda a interface. Você não escreve explicitamente a palavra-chave virtual na declaração da interface, nem usa a palavra-chave override na classe, elas estão implícitas.

A palavra-chave virtual é implementada no .NET com métodos e a chamada v-table, uma matriz de ponteiros de método. A palavra-chave override preenche o slot da tabela v com um ponteiro de método diferente, substituindo o produzido pela classe base. Propriedades, eventos e indexadores são implementados como métodos sob o capô. Mas os campos não são. As interfaces não podem, portanto, conter campos.

Hans Passant
fonte
Você forneceu o nome técnico / real (v-table) ao conceito de slots mencionado por Eric. Obrigado pelo detalhe Hans.
RBT 01/02
Qual seria o sentido de uma tabela v se as interfaces não implementassem implementações padrão? Isso muda no C # 8.0, mas isso não vem ao caso.
AnthonyMonterrosa 11/03
19

Por que não apenas ter uma Yearpropriedade, o que é perfeitamente bom?

As interfaces não contêm campos porque os campos representam uma implementação específica da representação de dados e a exposição deles quebraria o encapsulamento. Assim, ter uma interface com um campo seria efetivamente codificar para uma implementação em vez de uma interface, o que é um curioso paradoxo para uma interface!

Por exemplo, parte de sua Yearespecificação pode exigir que seja inválido para os ICarimplementadores permitir a atribuição a um período Yearposterior ao ano atual + 1 ou antes de 1900. Não há como dizer que se você tivesse exposto Yearcampos - é muito melhor usar propriedades em vez de fazer o trabalho aqui.

John Feminella
fonte
18

A resposta curta é sim, todo tipo de implementação precisará criar sua própria variável de suporte. Isso ocorre porque uma interface é análoga a um contrato. Tudo o que você pode fazer é especificar partes específicas de código acessíveis ao público que um tipo de implementação deve disponibilizar; não pode conter nenhum código em si.

Considere este cenário usando o que você sugere:

public interface InterfaceOne
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public interface InterfaceTwo
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public class MyClass : InterfaceOne, InterfaceTwo { }

Temos alguns problemas aqui:

  • Como todos os membros de uma interface são - por definição - públicos, nossa variável de suporte agora está exposta a qualquer pessoa que utilize a interface
  • Que myBackingVariablevai MyClassusar?

A abordagem mais comum adotada é declarar a interface e uma classe abstrata de barebones que a implementa. Isso permite a flexibilidade de herdar da classe abstrata e obter a implementação de graça, ou implementar explicitamente a interface e ter permissão para herdar de outra classe. Funciona mais ou menos assim:

public interface IMyInterface
{
    int MyProperty { get; set; }
}

public abstract class MyInterfaceBase : IMyInterface
{
    int myProperty;

    public int MyProperty
    {
        get { return myProperty; }
        set { myProperty = value; }
    }
}
Adam Robinson
fonte
7

Outros deram o 'Por que', então apenas acrescentarei que sua interface pode definir um Controle; se você o envolver em uma propriedade:

public interface IView {
    Control Year { get; }
}


public Form : IView {
    public Control Year { get { return uxYear; } } //numeric text box or whatever
}
zomf
fonte
3

As interfaces não contêm nenhuma implementação.

  1. Defina uma interface com uma propriedade.
  2. Além disso, você pode implementar essa interface em qualquer classe e usar essa classe daqui para frente.
  3. Se necessário, você pode ter essa propriedade definida como virtual na classe para poder modificar seu comportamento.
Amit
fonte
3

Muito já foi dito, mas para simplificar, aqui está minha opinião. As interfaces destinam-se a ter contratos de método a serem implementados pelos consumidores ou classes e não a ter campos para armazenar valores.

Você pode argumentar que, então, por que propriedades são permitidas? Portanto, a resposta simples é - as propriedades são definidas internamente como apenas métodos.

Prakash Tripathi
fonte
1
Se você precisar acessar um membro, basta torná-lo uma propriedade e você será bom.
Unome
0

Para isso, você pode ter uma classe base Car que implementa o campo year e todas as outras implementações podem herdar dele.


fonte
0

Uma interface define propriedades e métodos de instância pública . Os campos geralmente são privados ou, no máximo, protegidos, internos ou internos protegidos (o termo "campo" geralmente não é usado para nada público).

Conforme declarado por outras respostas, você pode definir uma classe base e definir uma propriedade protegida que será acessível por todos os herdeiros.

Uma peculiaridade é que uma interface pode de fato ser definida como interna, mas limita a utilidade da interface e é normalmente usada para definir a funcionalidade interna que não é usada por outro código externo.

Frode N. Rosand
fonte