Para a interface, a adição de abstract
, ou mesmo as public
palavras - chave seria redundante, então você as omite:
interface MyInterface {
void Method();
}
No CIL, o método é marcado virtual
e abstract
.
(Observe que o Java permite que os membros da interface sejam declarados public abstract
).
Para a classe de implementação, existem algumas opções:
Não substituível : Em C # a classe não declara o método como virtual
. Isso significa que ele não pode ser substituído em uma classe derivada (apenas oculto). No CIL o método ainda é virtual (mas selado) porque deve suportar polimorfismo em relação ao tipo de interface.
class MyClass : MyInterface {
public void Method() {}
}
Substituível : Tanto em C # quanto em CIL o método é virtual
. Ele participa do envio polimórfico e pode ser substituído.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explícito : esta é uma maneira de uma classe implementar uma interface, mas não fornecer os métodos de interface na interface pública da própria classe. No CIL, o método será private
(!), Mas ainda poderá ser chamado de fora da classe a partir de uma referência ao tipo de interface correspondente. Implementações explícitas também não podem ser substituídas. Isso é possível porque há uma diretiva CIL ( .override
) que vinculará o método privado ao método de interface correspondente que está implementando.
[C #]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
No VB.NET, você pode até mesmo criar um alias para o nome do método da interface na classe de implementação.
[VB.NET]
Public Class MyClass
Implements MyInterface
Public Sub AliasedMethod() Implements MyInterface.Method
End Sub
End Class
[CIL]
.method public newslot virtual final instance void AliasedMethod() cil managed
{
.override MyInterface::Method
}
Agora, considere este caso estranho:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
Se Base
e Derived
forem declarados no mesmo assembly, o compilador se tornará Base::Method
virtual e lacrado (no CIL), embora Base
não implemente a interface.
Se Base
e Derived
estiverem em assemblies diferentes, ao compilar o Derived
assembly, o compilador não mudará o outro assembly, portanto, apresentará um membro em Derived
que será uma implementação explícita para MyInterface::Method
que apenas delegue a chamada a Base::Method
.
Como você pode ver, toda implementação de método de interface deve suportar comportamento polimórfico e, portanto, deve ser marcada como virtual no CIL, mesmo que o compilador precise passar por muitos obstáculos para fazê-lo.
Sim, os métodos de implementação da interface são virtuais no que diz respeito ao tempo de execução. É um detalhe de implementação, faz as interfaces funcionarem. Os métodos virtuais obtêm slots na tabela v da classe, cada slot tem um ponteiro para um dos métodos virtuais. O lançamento de um objeto para um tipo de interface gera um ponteiro para a seção da tabela que implementa os métodos de interface. O código do cliente que usa a referência de interface agora vê o primeiro ponteiro de método de interface no deslocamento 0 do ponteiro de interface, etc.
O que eu subestimei em minha resposta original é o significado do atributo final . Impede que uma classe derivada substitua o método virtual. Uma classe derivada deve reimplementar a interface, os métodos de implementação sombreiam os métodos da classe base. O que é suficiente para implementar o contrato da linguagem C # que diz que o método de implementação não é virtual.
Se você declarar o método Dispose () na classe Example como virtual, verá o atributo final sendo removido. Agora permitindo que uma classe derivada o substitua.
fonte
Na maioria dos outros ambientes de código compilado, as interfaces são implementadas como vtables - uma lista de ponteiros para os corpos dos métodos. Normalmente, uma classe que implementa várias interfaces terá em algum lugar em seus metadados gerados pelo compilador interno uma lista de vtables de interface, uma vtable por interface (de modo que a ordem do método seja preservada). É assim que as interfaces COM também são normalmente implementadas.
No .NET, porém, as interfaces não são implementadas como vtables distintas para cada classe. Os métodos de interface são indexados por meio de uma tabela de método de interface global da qual todas as interfaces fazem parte. Portanto, não é necessário declarar um método virtual para que esse método implemente um método de interface - a tabela de métodos de interface global pode apenas apontar para o endereço de código do método da classe diretamente.
A declaração de um método virtual para implementar uma interface também não é necessária em outras linguagens, mesmo em plataformas não CLR. A linguagem Delphi no Win32 é um exemplo.
fonte
Eles não são virtuais (em termos de como pensamos neles, se não em termos de implementação subjacente como (virtual selado) - bom ler as outras respostas aqui e aprender algo eu mesmo :-)
Eles não substituem nada - não há implementação na interface.
Tudo o que a interface faz é fornecer um "contrato" ao qual a classe deve aderir - um padrão, se quiser, para que os chamadores saibam como chamar o objeto, mesmo que nunca tenham visto essa classe em particular antes.
Cabe à classe implementar o método da interface como desejar, dentro dos limites do contrato - virtual ou "não virtual" (virtual selado, como se revelou).
fonte
Interfaces são um conceito mais abstrato do que classes, quando você declara uma classe que implementa uma interface, você apenas diz "a classe deve ter esses métodos específicos da interface, e não importa se estático , virtual , não virtual , sobrescrito , como desde que tenha o mesmo ID e os mesmos parâmetros de tipo ".
Outras linguagens que suportam interfaces como Object Pascal ("Delphi") e Objective-C (Mac) também não requerem que os métodos de interface sejam marcados como virtuais e não virtuais.
Mas, você pode estar certo, acho que pode ser uma boa ideia ter um atributo "virtual" / "override" específico nas interfaces, caso você queira restringir os métodos de classes que implementam uma interface em particular. Mas, isso também significa ter palavras-chave "não virtuais", "dontcareifvirtualornot", para ambas as interfaces.
Eu entendo sua pergunta, porque vejo algo semelhante em Java, quando um método de classe tem que usar o "@virtual" ou "@override" para ter certeza de que um método se destina a ser virtual.
fonte
override
é uma palavra-chave de primeira classe no próprio idioma.