考虑这个愚蠢的程序,什么都不做:
- interface I<out T> { }
- class A1 : I<A1> { }
- class A2 : A1,I<A2> { }
- class B1 { }
- class B2 : B1,I<B2> { }
- class C1 : I<A1> { }
- class C2 : C1,I<A2> { }
- static class Program
- {
- static void f<T>(I<T> obj)
- {
- }
- static void Main()
- {
- f<A1>(new A2());
- f<A2>(new A2());
- f<B1>(new B2());
- f<B2>(new B2());
- f<A1>(new C2());
- f<A2>(new C2());
- }
- }
这表明,A2和C2实现了I< A1>和I A2,并且B2实现了两个I B1.和I B2.
但是,将其修改为
- static void Main()
- {
- f(new A2());
- f(new B2());
- f(new C2());
- }
表示在第一行和第三行,f的泛型类型参数不能从传递的参数推断,但在第二行,它可以是.
我明白编译器在这里做什么,所以不需要解释.但是我该如何解决这个问题?有没有办法修改这个,以便我可以在基类和派生类上定义接口,但是在传递派生类时,还有类型推断工作?
我想到的是寻找一种方法来“隐藏”一个基类实现的接口,这样编译器就不会看到它们并使用它们,即使它们存在.但是,C#似乎没有提供这样的选择.
澄清:在我的愚蠢的示例程序中,A1将自己实现为通用类型参数.我确实有我的真实代码,但我也有类实现我与一个不同的通用类型的参数,并添加了C1和C2到我的示例代码为此原因.
解决方法
使用两个F变体(第二个仅用于调用另一个的类型推断)和“继承”接口J继承自I,它不会像这样做:
- using System;
- using System.Threading;
- interface I<out T>
- {
- void Print();
- }
- interface J<out T> : I<T> { }
- class A : I<C>
- {
- void I<C>.Print()
- {
- Console.WriteLine("A: I<C>");
- }
- }
- class B {}
- class C : B { }
- class D1 : I<A>
- {
- void I<A>.Print()
- {
- Console.WriteLine("D1: I<A>");
- }
- }
- class D2 : D1,J<B>
- {
- void I<B>.Print()
- {
- Console.WriteLine("D2: I<B>");
- }
- }
- class D3 : D1,J<C>
- {
- void I<C>.Print()
- {
- Console.WriteLine("D3: I<C>");
- }
- }
- class D4 : A,J<B>
- {
- void I<B>.Print()
- {
- Console.WriteLine("D4: I<B>");
- }
- }
- static class Program
- {
- static void f<T>(J<T> obj)
- {
- f((I<T>)obj);
- }
- static void f<T>(I<T> obj)
- {
- obj.Print();
- }
- static void Main()
- {
- f<A>(new D2());
- f(new D2());
- f(new D3());
- f(new D4());
- f<C>(new D4());
- Console.ReadKey();
- }
- }
输出:
- D1: I<A>
- D2: I<B>
- D3: I<C>
- D4: I<B>
- A: I<C>