考虑这个愚蠢的程序,什么都不做:
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>