una que programacion polimorfismo orientada objetos interfaz interfaces implementacion herencia derivada clase abstracta c# interface

programacion - que es override en c#



¿Por qué es posible implementar un método de interfaz en la clase base? (10)

"Pero, ¿por qué A debería saber cómo implementar el método Foo de la interfaz IFoo? A ni siquiera sabe que existe IFoo".

A no necesita saber sobre la existencia de la interfaz IFoo. No es responsabilidad de A implementar FooMethod correctamente. Aparentemente A pasó a implementar el método que tiene la misma firma que el método de interfaz IFoo FooMethod.

Es responsabilidad de B implementar FooMethod, ya que implementa la interfaz IFoo. Pero como B ya tiene un método llamado FooMethod (heredado de A), no necesita implementarlo explícitamente. Si un método heredado no está haciendo su trabajo, B puede renovar el método y escribir su propia implementación.

En mi proyecto he encontrado una situación extraña que parece completamente válida en C #, porque no tengo errores de compilación.

El ejemplo simplificado se ve así:

using System; using System.Collections.Generic; namespace Test { interface IFoo { void FooMethod(); } class A { public void FooMethod() { Console.WriteLine("implementation"); } } class B : A, IFoo { } class Program { static void Main(string[] args) { IFoo foo = new B(); foo.FooMethod(); } } }

Tal código compila. Sin embargo, tenga en cuenta que A no es IFoo y B no implementa los métodos de IFoo . En mi caso, por accidente (después de la refactorización), A tiene el método con la misma firma. Pero, ¿por qué A debería saber cómo implementar el FooMethod de la interfaz IFoo ? Ni siquiera sabe que existen IFoo .

Para mi tener tal diseño es peligroso. Porque cada vez que implemento alguna interfaz debería comprobar si cada método en esta interfaz "interfiere" con los métodos de la clase base.

Si esto es "pura característica C #"? ¿Cómo se llama? ¿Me estoy perdiendo de algo?


La característica se llama herencia . Y si no te gusta el diseño, simplemente no lo uses. A mucha gente le disgusta la herencia, así que tú también puedes. La definición de herencia es que todos los miembros de la clase base también son miembros de la clase derivada. Así que no hay ningún error de compilación. Por lo tanto, Derived implementa el contrato que IFoo proporciona. Es el miembro de la clase base, que cumple con este requisito.

La belleza de esto es que puede implementar una interfaz a través de una funcionalidad básica (virtual), que se puede anular si se espera que un Derivado se comporte de manera diferente.


La palabra clave aquí es implements . Tu clase base, aunque no sabe nada sobre IFoo , se ha declarado la firma del método que implementa el método en tu interfaz en algún lugar de tu jerarquía de clases.

Entonces, cuando implementas IFoo en la clase derivada, ya tiene implementada la firma del método dentro de la estructura de la clase, por lo tanto, no es necesario implementarla nuevamente.

Si tuvieras esto:

interface IFoo { void FooMethod(); } class A { private void FooMethod(){} } class B : A, IFoo { }

IFoo implementar IFoo en este caso porque la estructura de IFoo no es accesible en el punto donde se implementa, y como dice Mark. Puede implementar implícitamente la interfaz haciendo IFoo.FooMethod() para asegurarse de que tiene una implementación a pesar de tener una firma de método adecuada ya definida en la jerarquía.


Las interfaces no se heredan, las interfaces se implementan. Así, cuando derivas una clase de una interfaz, significa

En esta interfaz, encontrará un método que implementa la firma de método que ha proporcionado.

Dado que la clase base tiene una implementación del método, con el mismo método definido en la interfaz, no habrá problemas.

Incluso si escribe una segunda interfaz con la misma firma de método, seguirá funcionando.

interface IFoo2 { void FooMethod(); } class B : A, IFoo, IFoo2 { }


Para cada miembro de la interfaz, el compilador simplemente busca una implementación explícita (si la hay), luego una implementación pública (implementación implícita ), es decir, un método en la API pública que coincida con la firma de la interfaz. En este caso, A.FooMethod() parece una buena A.FooMethod() para una implementación pública. Si B no estaba contento con esa selección, podría cambiar el método o usar una implementación explícita; este último sería el preferido:

void IFoo.FooMethod() { /* explicit implementation */ }


Para implementar una interfaz, una clase solo necesita (a) declarar que está implementando esa interfaz (como lo hace su clase B), y (b) proporcionar implementaciones para todos los métodos definidos en la interfaz, ya sea directa o indirectamente a través de clase base (como lo hace su clase B).


Sección 13.4.4. de los estados de especificación de C #:

La asignación de interfaz para una clase o estructura C ubica una implementación para cada miembro de cada interfaz especificada en la lista de clases base de C. La implementación de un IM de miembro de interfaz particular, donde I es la interfaz en la que se declara el miembro M, se determina examinando cada clase o estructura S, comenzando con C y repitiendo para cada clase base sucesiva de C, hasta que se encuentre una coincidencia:

Parece que este es un comportamiento bien definido, ya que la implementación correcta de FooMethod no se encuentra en B , por lo que se realiza una búsqueda en su clase base A donde se encuentra un método con la firma correspondiente. Esto incluso se señala explícitamente en la misma sección de la especificación:

Los miembros de una clase base participan en el mapeo de interfaces. En el ejemplo

interface Interface1 { void F(); } class Class1 { public void F() {} public void G() {} } class Class2: Class1, Interface1 { new public void G() {} }

el método F en Class1 se usa en la implementación de Class1 de Interface1.


Si bien no es particularmente útil especular sobre por qué los creadores de C # hicieron lo que hicieron, y si bien no me gusta esta característica en particular, sospecho que parte de la razón por la que funciona es que no existe otra sintaxis buena para especifique que una interfaz debe implementarse mediante un método de clase base ya existente. Requerir que la clase derivada debe definir métodos que no hagan nada más que encadenar a la implementación de la clase base parecería feo.

Dicho esto, creo que habría sido más limpio para C # resolver ese problema general (los métodos de interfaz que encadenan a otros miembros son feos) al proporcionar una sintaxis para adjuntar explícitamente un miembro de interfaz a un miembro de la clase, que usar el enlace automático semántica para manejar una situación particular, pero requiere el encadenamiento en una situación más común (implementación de la interfaz mediante un método virtual protegido):

IFoo_Method virtual protegido (int a, int b, int c) {...}

IFoo.Method (int a, int b, int c) {IFoo_Method (a, b, c); }

Si bien el JITter puede darse cuenta de que la llamada IFoo_Method debería estar en línea, realmente no debería tener que hacerlo. Parecería más limpio declarar que el método protegido IFoo_Method debe considerarse como la implementación de IFoo.Method .


Usted dice en un comentario,

¿ FooMethod tan probable es que el que escribió la implementación de FooMethod en A clase A que no implementa IFoo realmente haya querido implementar IFoo ?

Bueno, no importa lo que el escritor de A pensó en el momento de la creación de A Es el autor de B quien debe responsabilizarse por el hecho de que B hereda de A AND implementa IFoo . Depende del autor de B pensar en las consecuencias de la definición de B

Tu tambien dices

En mi caso por accidente (después de refactorizar) A tiene el método con la misma firma.

sugiriendo que esta situación se produjo después de que A y B hubieran sido escritos. En ese caso, la situación cambia: cuando se edita una clase que es * heredada de * (como A ), es responsabilidad del editor verificar los efectos de la edición en todas las clases heredadas.


B hacer implementar IFOO . B hereda de A por lo que en realidad se ve así:

class B : IFoo //Notice there is no A here. { public void FooMethod() { Console.WriteLine("implementation"); } }

Y está claro (a partir del código anterior) que B está implementando IFoo y que nada es especial.