Para la interfaz, la adición de abstract
, o incluso las public
palabras clave sería redundante, por lo que las omite:
interface MyInterface {
void Method();
}
En el CIL, el método está marcado virtual
y abstract
.
(Tenga en cuenta que Java permite declarar miembros de la interfaz public abstract
).
Para la clase de implementación, hay algunas opciones:
No reemplazable : en C #, la clase no declara el método como virtual
. Eso significa que no se puede anular en una clase derivada (solo oculta). En el CIL, el método sigue siendo virtual (pero sellado) porque debe admitir polimorfismo con respecto al tipo de interfaz.
class MyClass : MyInterface {
public void Method() {}
}
Reemplazable : tanto en C # como en CIL, el método es virtual
. Participa en el envío polimórfico y se puede anular.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explícito : esta es una forma para que una clase implemente una interfaz pero no proporcione los métodos de interfaz en la interfaz pública de la clase en sí. En el CIL, el método será private
(!) Pero aún se podrá llamar desde fuera de la clase desde una referencia al tipo de interfaz correspondiente. Las implementaciones explícitas tampoco son reemplazables. Esto es posible porque hay una directiva CIL ( .override
) que vinculará el método privado al método de interfaz correspondiente 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
}
En VB.NET, incluso puede alias el nombre del método de interfaz en la clase de implementación.
[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
}
Ahora, considere este extraño caso:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
Si Base
y Derived
se declaran en el mismo ensamblado, el compilador lo hará Base::Method
virtual y sellado (en el CIL), aunque Base
no implemente la interfaz.
Si Base
y Derived
están en diferentes ensamblados, al compilar el Derived
ensamblado, el compilador no cambiará el otro ensamblado, por lo que introducirá un miembro Derived
que será una implementación explícita para MyInterface::Method
que solo delegará la llamada a Base::Method
.
Como puede ver, cada implementación de método de interfaz debe admitir un comportamiento polimórfico y, por lo tanto, debe marcarse como virtual en el CIL, incluso si el compilador debe pasar por aros para hacerlo.
Sí, los métodos de implementación de la interfaz son virtuales en lo que respecta al tiempo de ejecución. Es un detalle de implementación, hace que las interfaces funcionen. Los métodos virtuales obtienen ranuras en la tabla v de la clase, cada ranura tiene un puntero a uno de los métodos virtuales. La conversión de un objeto a un tipo de interfaz genera un puntero a la sección de la tabla que implementa los métodos de interfaz. El código de cliente que usa la referencia de interfaz ahora ve el primer puntero de método de interfaz en el desplazamiento 0 del puntero de interfaz, etcétera.
Lo que menosprecié en mi respuesta original es el significado del atributo final . Evita que una clase derivada anule el método virtual. Una clase derivada debe volver a implementar la interfaz, los métodos de implementación hacen sombra a los métodos de la clase base. Lo cual es suficiente para implementar el contrato de lenguaje C # que dice que el método de implementación no es virtual.
Si declara el método Dispose () en la clase Example como virtual, verá que se elimina el atributo final . Ahora permite que una clase derivada lo anule.
fuente
En la mayoría de los demás entornos de código compilado, las interfaces se implementan como vtables, una lista de punteros a los cuerpos del método. Normalmente, una clase que implementa múltiples interfaces tendrá en algún lugar de sus metadatos generados por el compilador interno una lista de vtables de interfaz, una vtable por interfaz (para que se mantenga el orden del método). Así es como se implementan normalmente las interfaces COM.
En .NET, sin embargo, las interfaces no se implementan como tablas virtuales distintas para cada clase. Los métodos de interfaz se indexan a través de una tabla de métodos de interfaz global de la que forman parte todas las interfaces. Por lo tanto, no es necesario declarar un método virtual para que ese método implemente un método de interfaz; la tabla de métodos de interfaz global puede apuntar directamente a la dirección de código del método de la clase.
La declaración de un método virtual para implementar una interfaz tampoco es necesaria en otros lenguajes, incluso en plataformas que no son CLR. El lenguaje Delphi en Win32 es un ejemplo.
fuente
No son virtuales (en términos de cómo pensamos en ellos, si no en términos de implementación subyacente como (virtual sellado) - es bueno leer las otras respuestas aquí y aprender algo yo mismo :-)
No anulan nada, no hay implementación en la interfaz.
Todo lo que hace la interfaz es proporcionar un "contrato" al que la clase debe adherirse, un patrón, si lo desea, para que las personas que llaman sepan cómo llamar al objeto incluso si nunca antes han visto esa clase en particular.
Depende de la clase implementar el método de interfaz como lo hará, dentro de los límites del contrato: virtual o "no virtual" (virtual sellado, según parece).
fuente
Las interfaces son un concepto más abstracto que las clases, cuando declaras una clase que implementa una interfaz, simplemente dices "la clase debe tener estos métodos particulares de la interfaz, y no importa si estática , virtual , no virtual , anulada , como siempre que tenga el mismo ID y los mismos parámetros de tipo ".
Otros lenguajes que admiten interfaces como Object Pascal ("Delphi") y Objective-C (Mac) no requieren que los métodos de interfaz se marquen como virtuales y no virtuales.
Pero, puede que tenga razón, creo que puede ser una buena idea tener un atributo "virtual" / "override" específico en las interfaces, en caso de que desee restringir los métodos de clases que implementan una interfaz en particular. Pero, eso también significa tener palabras clave "no virtual", "dontcareifvirtualornot", para ambas interfaces.
Entiendo su pregunta, porque veo algo similar en Java, cuando un método de clase tiene que usar "@virtual" o "@override" para estar seguro de que un método está destinado a ser virtual.
fuente
override
es una palabra clave de primera clase en el propio idioma.