what tutorial property mvc multiples multiple interfaces implement are c# inheritance interface-implementation

c# - tutorial - Interfaz implementada dos veces "los tipos pueden unificar"; ¿Por qué funciona esta solución?



what are generics in c# (3)

Considere esta implementación:

public class MyClass<T1, T2> : IMyInterface<T1, T2>, IMyInterface<T2, T1> { /* implementation for IMyInterface<T1, T2> here. */ /* implementation for IMyInterface<T2, T1> here. */ }

¿Qué implementa MyClass<int, int> ? Implementa IMyInterface<int, int> dos veces, porque IMyInterface<T1, T2> y IMyInterface<T2, T1> unifican cuando T1 y T2 son iguales. Es por eso que no se IMyInterface<T1, T2> implementar IMyInterface<T1, T2> e IMyInterface<T2, T1> en la misma clase. El mismo razonamiento se aplicaría si intentara implementar, por ejemplo, IMyInterface<int, T1> e IMyInterface<T2, double> : las expresiones de tipo se unifican para T1 = double, T2 = int .

Considere esta implementación:

public class MyClass<T1, T2> : MyClassBase<T1, T2>, IMyInterface<T1, T2> { /* implementation for IMyInterface<T1, T2> here. */ } public class MyClassBase<T1, T2> : IMyInterface<T2, T1> { /* implementation for IMyInterface<T2, T1> here. */ }

Lo que has hecho es colocar una prioridad en IMyInterface<T1, T2> sobre IMyInterface<T2, T1> . En el caso de que T1 y T2 sean iguales y tenga una instancia de MyClass<T1, T2> , se seleccionará la IMyInterface<T1, T2> . Si tiene una instancia de MyBaseClass<T1, T2> , se seleccionará la IMyInterface<T2, T1> .

Aquí hay un programa de juguetes que te muestra los comportamientos. En particular, observe el comportamiento de a_as_i.M(0, 1) y a_as_b.M(0, 1) . Si tuviera que implementar I<T2, T1> explícitamente en B<T1, T2> (prefijando el nombre del método con I<T2, T1>. ), sería imposible llamarlo usando la sintaxis de tiempo de compilación. La reflexión sería necesaria.

interface I<T1, T2> { void M(T1 x, T2 y); } class A<T1, T2> : B<T1, T2>, I<T1, T2> { public void M(T1 x, T2 y) { Console.WriteLine("A: M({0}, {1})", x, y); } } class B<T1, T2> : I<T2, T1> { public void M(T2 x, T1 y) { Console.WriteLine("B: M({0}, {1})", x, y); } } class Program { static void Main(string[] args) { //Outputs "A: M(0, 1)" var a = new A<int, int>(); a.M(0, 1); //Outputs "B: M(0, 1)" var b = new B<int, int>(); b.M(0, 1); //Outputs "A: M(0, 1)" because I<T1, T2> //takes precedence over I<T2, T1> var a_as_i = a as I<int, int>; a_as_i.M(0, 1); //Outputs "B: M(0, 1)" despite being called on an instance of A var a_as_b = a as B<int, int>; a_as_b.M(0, 1); Console.ReadLine(); } }

Me he topado con un error del compilador al intentar implementar una interfaz dos veces para la misma clase, por lo que:

public class Mapper<T1, T2> : IMapper<T1, T2>, IMapper<T2, T1> { /* implementation for IMapper<T1, T2> here. */ /* implementation for IMapper<T2, T1> here. */ }

El error:

''Mapper'' no puede implementar tanto ''IMapper'' como ''IMapper'' porque pueden unificar para algunas sustituciones de parámetros de tipo.

¿Por qué funciona esta solución? Me pregunto si he resuelto el problema o si he engañado al compilador.

public class Mapper<T1, T2> : MapperBase<T1, T2>, IMapper<T1, T2> { /* implementation for IMapper<T1, T2> here. */ } public class MapperBase<T1, T2> : IMapper<T2, T1> { /* implementation for IMapper<T2, T1> here. */ }

EDITAR : He actualizado MyClass , MyClassBase e IMyInterface a Mapper , MapperBase e IMapper para representar un escenario más real en el que este problema puede presentarse.


Creo que el problema es causado por la incapacidad del compilador para revelar cuál de los métodos implementados debería invocarse si uno de los tipos T1 o T2 es descendiente de otro (o es el mismo tipo).
Imagínese qué debería hacer si crea una instancia de la clase MyClass<int, int> .


No has engañado al compilador, lo has hecho para que no tengas definiciones de funciones en competencia. Supongamos que su interfaz tiene la función string Convert(T1 t1, T2 t2) . Con su primer código (ilegal), si hiciera MyClass<string, string> , tendría 2 instancias de la misma función. Con su clase base, esas 2 instancias estarán en MyClassBase y MyClass , por lo que la de MyClass OCULTARÁ la otra, en lugar de estar en conflicto con eso. Si eso funciona o no depende de ti, supongo.