usan una que programacion poo polimorfismo las interfaz interfaces herencia como clases clase abstractas abstracta c# methods interface abstract virtual-functions

c# - programacion - que es una clase abstracta



¿Por qué los métodos de la interfaz C#no se declaran abstractos o virtuales? (6)

Los métodos C # en las interfaces se declaran sin utilizar la palabra clave virtual , y se invalidan en la clase derivada sin utilizar la palabra clave override .

¿Hay alguna razón para esto? Supongo que es solo una conveniencia de lenguaje, y obviamente el CLR sabe cómo manejar esto bajo la tapa (los métodos no son virtuales por defecto), pero ¿hay otras razones técnicas?

Aquí está el IL que genera una clase derivada:

class Example : IDisposable { public void Dispose() { } } .method public hidebysig newslot virtual final instance void Dispose() cil managed { // Code size 2 (0x2) .maxstack 8 IL_0000: nop IL_0001: ret } // end of method Example::Dispose

Observe que el método se declara virtual final en el IL.


<chiste> Esto es algo que quizás quiera preguntarle a Anders Hejlsberg y al resto del equipo de diseño de C #. </ joke>

Las interfaces son un concepto más abstracto que las clases, cuando declaras una clase que implementa una interfaz, solo dices "la clase debe tener estos métodos particulares de la interfaz, y no importa si estática , virtual , no virtual , sobrescrita , como siempre y cuando tenga la misma 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 tampoco virtuales.

Pero, puede que tengas razón, creo que puede ser una buena idea tener un atributo específico "virtual" / "anular" en las interfaces, en caso de que quieras restringir los métodos de las clases que implementan una interfaz en particular. Pero eso también significa tener una palabra 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 asegurarse de que un método sea virtual.


Citando a Jeffrey Ritcher de CLR vía CSharp 3rd Edition aquí

El CLR requiere que los métodos de interfaz se marquen como virtuales. Si no marca explícitamente el método como virtual en su código fuente, el compilador marca el método como virtual y sellado; esto evita que una clase derivada anule el método de interfaz. Si marca explícitamente el método como virtual, el compilador marca el método como virtual (y lo deja sin sellar); esto permite que una clase derivada anule el método de interfaz. Si un método de interfaz está sellado, una clase derivada no puede anular el método. Sin embargo, una clase derivada puede volver a heredar la misma interfaz y puede proporcionar su propia implementación para los métodos de la interfaz.


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 de métodos. Normalmente, una clase que implementa múltiples interfaces tendrá en algún lugar de sus metadatos generados por el compilador interno una lista de tablas de interfaz, una tabla por interfaz (para que el orden del método se conserve). Así es como las interfaces COM también se implementan típicamente.

En .NET, sin embargo, las interfaces no se implementan como tablas 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étodo de interfaz global puede apuntar directamente a la dirección de código del método de la clase.

Tampoco se requiere declarar un método virtual para implementar una interfaz en otros lenguajes, incluso en plataformas que no son CLR. El lenguaje Delphi en Win32 es un ejemplo.


No son virtuales (en términos de cómo pensamos en ellos, si no en términos de implementación subyacente como (sellado virtual) - bueno para 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 tiene que adherirse, un patrón, si lo desea, para que las personas que llaman sepan cómo llamar al objeto incluso si nunca antes lo habían visto.

Depende de la clase el implementar el método de interfaz como lo hará, dentro de los límites del contrato: virtual o "no virtual" (sellado virtual como resulta).


Para la interfaz, la adición del abstract , o incluso de las palabras clave public sería redundante, por lo que las omite:

interface MyInterface { void Method(); }

En el CIL, el método se marca como virtual y abstract .

(Tenga en cuenta que Java permite que los miembros de la interfaz sean declarados public abstract ).

Para la clase de implementación, hay algunas opciones:

No invalidable : en C #, la clase no declara el método como virtual . Eso significa que no puede ser anulado en una clase derivada (solo oculta). En el CIL, el método sigue siendo virtual (pero sellado) porque debe soportar el polimorfismo en relación con el tipo de interfaz.

class MyClass : MyInterface { public void Method() {} }

Anulable : tanto en C # como en CIL, el método es virtual . Participa en el envío polimórfico y puede anularse.

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 el CIL, el método será private (!) Pero aún así se podrá llamar desde fuera de la clase desde una referencia al tipo de interfaz correspondiente. Las implementaciones explícitas tampoco son invalidables. Esto es posible porque hay una directiva CIL ( .override ) que vinculará el método privado con el método de interfaz correspondiente que está implementando.

[DO#]

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, considera 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 hará Base::Method virtual y sellado (en el CIL), aunque Base no implemente la interfaz.

Si Base y Derived están en ensamblajes diferentes, al compilar el ensamblado Derived , el compilador no cambiará el otro ensamblado, por lo que introducirá un miembro en Derived que será una implementación explícita para MyInterface::Method que simplemente delegará la llamada a Base::Method .

Como puede ver, todas las implementaciones de métodos de interfaz deben admitir el comportamiento polimórfico y, por lo tanto, deben estar marcadas como virtuales en el CIL, incluso si el compilador debe pasar por aros para hacerlo.


Sí, los métodos de implementación de 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 clase ''v-table'', cada ranura tiene un puntero a uno de los métodos virtuales. Al convertir un objeto en un tipo de interfaz se genera un puntero a la sección de la tabla que implementa los métodos de interfaz. El código de cliente que utiliza la referencia de interfaz ahora ve el puntero del primer método de interfaz en el desplazamiento 0 desde el puntero de la interfaz, etcétera.

Lo que menosprecio en mi respuesta original es la importancia del atributo final . Impide que una clase derivada anule el método virtual. Una clase derivada debe volver a implementar la interfaz, los métodos de implementación ocultan 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 permitiendo que una clase derivada lo anule.