使用通用接口约束时的协方差/逆差异难题

public interface IShape{} public class Rectangle : IShape{} public class Base{} public class Derived : Base{} public interface IFoo where T : IShape where U : Base { T Convert(U myType); } public class MyFoo : IFoo { public Rectangle Convert(Derived myType) { throw new NotImplementedException(); } } class Program { static void Main(string[] args) { IFoo hmm = new MyFoo(); } } 

鉴于上面的代码,编译器无法确定如何将类型MyFoo分配给IFoo MyFoo IFoo ,可能是因为U被设置为out意味着它可以接受更少的派生。 但是, DerivedBase更加派生,因此会生成编译器错误。

这个例子是设计的,但我们正在处理的实现是从工厂返回MyFoo实现。

尽管U用作参数,但在尝试将其分配给通用接口时它也是输出,但我无法在此处使用out关键字。 我们怎么能解决这个问题呢?

您的IFoo界面在这种用法中似乎是错误的,它应该是:

 public interface IFoo 

随着U出局。 请记住, outgenerics类型参数意味着它可以“向外”变化。 也就是说,您可以隐式地将类型扩展为更宽的类型。 但是,意味着您可以隐式地将“内部”类型缩小为更具体的类型。 当然,这些只是粗略的类比。

因此,在分配hmm的情况下,您隐式尝试将U的接口generics类型参数从Derived扩展为Base ,但接口声明它正在缩小( in ):

 IFoo hmm = new MyFoo(); 

所以它无法进行隐式转换。 如果你真的希望能够隐式地扩展这个接口,那么第二个类型的参数应该是out而不是in

更新:在您的评论之后,我发现最大的难题是您希望它既可以进出也不可能因为它是一个逆变输入,您不能将该接口共同分配给IFoo ,不幸的是。

您需要围绕无法分配给IFoo的事实进行编码IFoo或者您可以做的是创建Foo:

public class MyFoo : IFoo

然后在实现内部转换为Rectangle 。 最重要的是你不能在同一类型参数上同时具有协方差和逆变。

这有意义吗?

可以将Base转换为Rectangle的东西也会将Derived转换为IShape。 但是,可以将Derived转换为Rectangle的东西可能无法对Base执行任何有用的操作。 您正确地确定了第二个参数的协方差说明符需要“in”,但是然后尝试以与它实际支持的方式相反的方式使用协方差。