Descubrí que al insertar una clase entre una interfaz y otra clase derivada, se llama a la implementación predeterminada de la interfaz en lugar de a la implementación derivada del mismo método. Este es un comportamiento inesperado. ¿Por qué está pasando esto?
He creado un proyecto de muestra que reproduce el problema:
public interface IPrinterInterface { public void PrintIt() => Console.WriteLine("Interface"); } public class MiddlePrinter : IPrinterInterface{} public class Printer : MiddlePrinter { public void PrintIt() => Console.WriteLine("Class"); } class Program { static void Main(string[] args) { var printer = (IPrinterInterface)new Printer(); printer.PrintIt(); // This prints "Interface" Console.ReadLine(); // so the app sits } } Este código da como resultado que se imprima la Interface .
Por el contrario, si la clase MiddlePrinter se elimina de la herencia (como se muestra en el siguiente código), el código imprime "Clase":
public interface IPrinterInterface { public void PrintIt() => Console.WriteLine("Interface"); } public class Printer : IPrinterInterface { public void PrintIt() => Console.WriteLine("Class"); } class Program { static void Main(string[] args) { var printer = (IPrinterInterface)new Printer(); printer.PrintIt(); // This prints "Class" Console.ReadLine(); // so the app sits } }No esperaba ver este tipo de comportamiento, ¿alguien puede explicar por qué sucede esto?
Esto se ha reproducido en una aplicación de consola .NET5 y una aplicación moderna de Android Xamarin.
Las clases no heredan miembros de las interfaces, ni siquiera con las implementaciones predeterminadas. fuente
Tenga en cuenta que una clase no hereda miembros de sus interfaces; eso no cambia con esta característica
Como tal, dado que MiddlePrinter no contiene un miembro heredado para que Printer lo anule, la implementación más concreta de PrintIt() desde el punto de vista de IPrinterInterface es su propia implementación predeterminada.
Esto se hace evidente al intentar aplicar la palabra clave override a Printer.PrintIt() . Obtendrá un error que indica que no se encontró ningún método adecuado para anular.
Sin MiddlePrinter , Printer proporciona una implementación más concreta al reemplazar el valor predeterminado.
La razón es que cuando se convierte a una interfaz, intenta encontrar la primera función que está en el mismo nivel de herencia que la interfaz o en un nivel de herencia más bajo (misma clase o clase principal). Debido a que definió la funcionalidad para la interfaz ( función de respaldo predeterminada ), no puede encontrar una función adecuada para anular y simplemente vuelve a la función predeterminada especificada en la interfaz.
Por ejemplo, he agregado otra impresora llamada Impresora Lower :
public interface IPrinterInterface { // Default function if no parent functions are found. public void PrintIt() => Console.WriteLine("Interface"); } public class LowerPrinter { public void PrintIt() => Console.WriteLine("Lower"); } public class MiddlePrinter : LowerPrinter, IPrinterInterface { } public class Printer : MiddlePrinter { public void PrintIt() => Console.WriteLine("Class"); } internal class Program { private static void Main(string[] args) { var printer = (IPrinterInterface)new Printer(); printer.PrintIt(); // This prints "Lower" Console.ReadLine(); // so the app sits } }Pero ahora si lo extiendo más:
public class BasePrinter { public void PrintIt() => Console.WriteLine("Base"); } public class LowerPrinter : BasePrinter { public void PrintIt() => Console.WriteLine("Lower"); } Seguirá imprimiendo Lower porque es la primera función adecuada que se encuentra. La razón por la que no puede buscar en las clases secundarias o derivadas es porque no hay garantía de que la función lo haga en esas clases. Podría estar pensando " ¿pero cómo heredan? " - Porque si la clase secundaria tiene una función con el mismo nombre, oculta el método principal, no lo implementa.