简体   繁体   English

接口实现两次“类型可以统一”; 为什么这个解决方法有效?

[英]Interface implemented twice “types may unify”; why does this workaround work?

I've run into a compiler error when attempting to implement an interface twice for the same class like so: 尝试为同一个类实现两次接口时遇到编译器错误,如下所示:

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

   /* implementation for IMapper<T2, T1> here.  */
}

The error: 错误:

'Mapper' cannot implement both 'IMapper' and 'IMapper' because they may unify for some type parameter substitutions. 'Mapper'无法同时实现'IMapper'和'IMapper',因为它们可能会统一某些类型参数替换。

Why does this workaround work? 为什么这个解决方法有效? I'm wondering if I've solved the problem or just tricked the compiler. 我想知道我是否已经解决了问题或者只是欺骗了编译器。

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. */
}

EDIT : I've updated MyClass , MyClassBase , and IMyInterface to Mapper , MapperBase , and IMapper to represent a more real-world scenario where this issue may present itself. 编辑 :我已经更新MyClassMyClassBaseIMyInterfaceMapperMapperBaseIMapper代表一个更真实的场景,这个问题可以提出自己。

Consider this implementation: 考虑这个实现:

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

   /* implementation for IMyInterface<T2, T1> here.  */
}

What does MyClass<int, int> implement? MyClass<int, int>实现了什么? It implements IMyInterface<int, int> twice, because IMyInterface<T1, T2> and IMyInterface<T2, T1> unify when T1 and T2 are equal. 它实现两次IMyInterface<int, int> ,因为当T1T2相等时, IMyInterface<T1, T2>IMyInterface<T2, T1>统一。 That's why implementing both IMyInterface<T1, T2> and IMyInterface<T2, T1> on the same class is disallowed. 这就是为什么不允许在同一个类上实现IMyInterface<T1, T2>IMyInterface<T2, T1>的原因。 The same reasoning would apply if you tried to implement, for example, IMyInterface<int, T1> and IMyInterface<T2, double> : the type expressions unify for T1 = double, T2 = int . 如果你试图实现相同的推理,例如, IMyInterface<int, T1>IMyInterface<T2, double> :类型表达式统一为T1 = double, T2 = int

Consider this implementation: 考虑这个实现:

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. */
}

What you've done is place a priority on IMyInterface<T1, T2> over IMyInterface<T2, T1> . 你所做的是优先考虑IMyInterface<T1, T2>不是IMyInterface<T2, T1> In the event that T1 and T2 are equal and you have an instance of MyClass<T1, T2> , the IMyInterface<T1, T2> implementation will be selected. 如果T1T2相等并且您有MyClass<T1, T2>的实例,则将选择IMyInterface<T1, T2>实现。 If you have an instance of MyBaseClass<T1, T2> , the IMyInterface<T2, T1> implementation will be selected. 如果您有MyBaseClass<T1, T2>的实例, MyBaseClass<T1, T2> IMyInterface<T2, T1>实现。

Here's a toy program that shows you the behaviors. 这是一个玩具程序,向您展示行为。 In particular notice the behavior of a_as_i.M(0, 1) and a_as_b.M(0, 1) . 特别注意a_as_i.M(0, 1)a_as_b.M(0, 1) If you were to implement I<T2, T1> explicitly on B<T1, T2> (by prefixing the method name with I<T2, T1>. ), it would be impossible to call it using compile-time syntax. 如果要在B<T1, T2>上明确地实现I<T2, T1> (通过在方法名前加上I<T2, T1>. ),则不可能使用编译时语法来调用它。 Reflection would be necessary. 反思是必要的。

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();
    }
}

You haven't tricked the compiler, you've made it so that you won't have competing function definitions. 你没有欺骗编译器,你已经做到了这样你就不会有竞争的函数定义。 Assume your interface has the function string Convert(T1 t1, T2 t2) . 假设您的接口具有函数string Convert(T1 t1, T2 t2) With your first (illegal) code, if you did MyClass<string, string> , you would have 2 instances of the same function. 使用您的第一个(非法)代码,如果您使用MyClass<string, string> ,您将拥有2个相同功能的实例。 With your base class, those 2 instances will be in MyClassBase and MyClass , so the one in MyClass will HIDE the other one, instead of conflict with that. 随着你的基类,这些2个实例将在MyClassBaseMyClass ,所以一个在MyClass会隐藏,而不是与冲突的另外一个。 Whether that works or not is up to you, I suppose. 我想,无论是否有效取决于你。

I believe the problem is caused by unability of the compiler to reveal which of the implemented methods should be invoked if one of the T1 or T2 types is descendant of another (or is the same type). 我认为这个问题是由于编译器无法显示如果T1T2类型之一是另一个(或者是相同类型)的后代,应该调用哪些已实现的方法。
Imagine what should it do if you instantiate the class MyClass<int, int> . 想象一下,如果实例化MyClass<int, int>类,它应该怎么做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM