Por exemplo, suponha que eu queira uma ICar
interface 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?
Por exemplo, suponha que eu queira uma ICar
interface 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?
Respostas:
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.
An interface cannot contain constants, fields, operators
Do. msdn.microsoft.com/en-us/library/ms173156.aspx )
int One()
, a implementação public int One(){return 1;}
não é um campo.
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
}
Year
?
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; }
Declare-o como uma propriedade:
interface ICar {
int Year { get; set; }
}
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.
Por que não apenas ter uma Year
propriedade, 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 Year
especificação pode exigir que seja inválido para os ICar
implementadores permitir a atribuição a um período Year
posterior ao ano atual + 1 ou antes de 1900. Não há como dizer que se você tivesse exposto Year
campos - é muito melhor usar propriedades em vez de fazer o trabalho aqui.
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:
myBackingVariable
vai MyClass
usar?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; }
}
}
As interfaces não contêm nenhuma implementação.
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.
Para isso, você pode ter uma classe base Car que implementa o campo year e todas as outras implementações podem herdar dele.
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.