首页 文章

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

提问于
浏览
19

尝试为同一个类实现两次接口时遇到编译器错误,如下所示:

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

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

错误:

'Mapper'无法同时实现'IMapper'和'IMapper',因为它们可能会统一某些类型参数替换 .

为什么这个解决方法有效?我想知道我是否已经解决了问题或者只是欺骗了编译器 .

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 :我已将 MyClassMyClassBaseIMyInterface 更新为 MapperMapperBaseIMapper ,以表示此问题可能出现的更真实场景 .

3 回答

  • 21

    考虑这个实现:

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

    MyClass<int, int> 实施了什么?它实现 IMyInterface<int, int> 两次,因为 IMyInterface<T1, T2>IMyInterface<T2, T1>T1T2 相等时统一 . 这就是为什么不允许在同一个类上实现 IMyInterface<T1, T2>IMyInterface<T2, T1> 的原因 . 如果您尝试实现相同的推理,例如, IMyInterface<int, T1>IMyInterface<T2, double> :类型表达式统一为 T1 = double, T2 = int .

    考虑这个实现:

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

    你所做的是优先考虑 IMyInterface<T1, T2> 超过 IMyInterface<T2, T1> . 如果 T1T2 相等且您有 MyClass<T1, T2> 的实例,则将选择 IMyInterface<T1, T2> 实现 . 如果您有 MyBaseClass<T1, T2> 的实例,则将选择 IMyInterface<T2, T1> 实现 .

    这是一个玩具程序,向您展示行为 . 特别注意 a_as_i.M(0, 1)a_as_b.M(0, 1) 的行为 . 如果要在 B<T1, T2> 上显式实现 I<T2, T1> (通过在 I<T2, T1>. 前面加上方法名称),则无法使用编译时语法调用它 . 反思是必要的 .

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

    你没有't tricked the compiler, you'已经做到这一点,所以你不会有竞争的功能定义 . 假设您的界面具有 string Convert(T1 t1, T2 t2) 函数 . 使用您的第一个(非法)代码,如果您执行 MyClass<string, string> ,则您将拥有2个相同功能的实例 . 使用您的基类,这两个实例将位于 MyClassBaseMyClass 中,因此 MyClass 中的一个将隐藏另一个实例,而不是与之冲突 . 我想,无论是否有效取决于你 .

  • 1

    我认为问题是由于编译器无法显示如果其中一个 T1T2 类型是另一个类型的后代(或者是相同类型),则应该调用哪些已实现的方法 .
    想象一下如果你实例化类 MyClass<int, int> 应该怎么做 .

相关问题