public interface IShape{}
public class Rectangle : IShape{}
public class Base{}
public class Derived : Base{}
public interface IFoo<out T, in U>
where T : IShape
where U : Base
{
T Convert(U myType);
}
public class MyFoo : IFoo<Rectangle, Derived>
{
public Rectangle Convert(Derived myType)
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
IFoo<IShape, Base> hmm = new MyFoo();
}
}
给定上面的代码,编译器无法确定如何将类型MyFoo
分配给IFoo<IShape, Base>
,可能是因为U
被设置为out,这意味着它可以接受较少派生的类型。然而,Derived
比Base
派生得更多,因此会产生编译器错误。
这个例子是人为设计的,但我们正在处理的实现是从工厂返回MyFoo
的实现。
虽然U
被用作参数,但当试图将其分配给通用接口时,它也是一个输出,但我无法在此处使用out
关键字。我们如何解决这个问题?
您的IFoo接口在这种用法中似乎是错误的,它应该是:
public interface IFoo<out T, **out** U>
U
退出。请记住,out
泛型类型参数意味着它可以"向外"变化。也就是说,您可以隐式地将类型扩展为更宽的类型。然而,In
意味着您可以隐式地将类型"向内"缩小为更具体的类型。当然,这些只是粗略的类比。
因此,在分配hmm
的情况下,您隐含地试图将U
的接口泛型类型参数从Derived
扩展到Base
,但接口声明它正在缩小(in
(:
IFoo<IShape, Base> hmm = new MyFoo();
所以它不能进行隐式转换。如果您真的希望能够隐式扩展此接口,那么第二个类型参数应该是out
,而不是in
。
更新:在你的评论之后,我发现最大的困境是你希望它既输入又输出,这是不可能的。不幸的是,由于它是一个逆变输入,你不能将接口协变地分配给IFoo<IShape, Base>
。
您要么需要围绕无法分配给IFoo<IShape,Base>
的事实进行编码,要么可以将Foo创建为:
public class MyFoo : IFoo<Rectangle, Base>
然后在实现内部强制转换为Rectangle
。最重要的是,同一类型的参数不能同时具有协方差和反方差。
这有道理吗?
可以将Base转换为Rectangle的东西也会将Derived转换为IShape。然而,一些可以将"派生"转换为"矩形"的东西可能无法对"基"执行任何有用的操作。您正确地确定了第二个参数的协方差说明符需要为"in",但随后尝试以与实际支持相反的方式使用协方差。