使用通用接口约束时的协方差/逆差异难题 [英] Covariance/Contravariance Conundrum when using generic interface constraints
问题描述
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意味着它可以接受更少的派生。但是,派生
比 Base
派生的更多,因此会产生编译错误。
Given the above code, the compiler is unable to determine how to assign the type MyFoo
to IFoo<IShape, Base>
, presumably because U
is set as an out meaning that it can accept less derived. However, Derived
is, well, more derived than Base
, so generates a compiler error.
这个例子是设计的,但我们正在处理的实现是从工厂返回 MyFoo
的实现。
This example is contrived but the implementation we are dealing with is one in which MyFoo
would be returned from a factory.
虽然 U
用作参数,但在尝试将其分配给通用接口时它也是输出但我无法在此处使用 out
关键字。我们怎么能解决这个问题呢?
Although U
is used as a parameter, it is also an output when trying to assign it to the generic interface but I am unable to use the out
keyword here. How could we work around this?
推荐答案
你的IFoo界面在这个用法中似乎是错误的,它应该是:
Your IFoo interface seems to be wrong in this usage, it should be:
public interface IFoo<out T, **out** U>
U
退出。请记住, out
泛型类型参数意味着它可以向外变化。也就是说,您可以隐式地将类型扩展为更宽的类型。 但是,在
中,意味着您可以隐式地将内部类型缩小为更具体的类型。当然,这些只是粗略的类比。
With U
being out. Remember that an out
generic type parameter means that it can vary "outwards". That is, you can widen the type implicitly to a wider type. In
, though, means that you can implicitly narrow the type "inwards" to a more specific type. These are just rough analogies, of course.
因此,在分配 hmm
的情况下,你就是隐式尝试将 U
的接口泛型类型参数从派生
扩展为 Base
,但界面宣称它正在缩小( in
):
So in the case of the assignment of hmm
, you are are implicitly trying to widen the interface generic type parameter for U
from Derived
to Base
, but the interface declares it to be narrowing (in
):
IFoo<IShape, Base> hmm = new MyFoo();
因此无法进行隐式转换。如果你真的希望能够隐式地扩展这个接口,那么第二个类型的参数应该是 out
而不是中的。
So it can't make the implicit conversion. If you really want to be able to widen this interface implicitly, the second type argument should be out
instead of in
.
更新:在您的评论之后,我发现最大的困境是您希望它既可以进出也可以进入,这是不可能的因为它是一个逆变输入,遗憾的是,你无法将界面协调地分配给 IFoo< IShape,Base>
。
Update: after your comments, I see that the big dilemma is that you want it to be both in and out, which isn't really possible Since it's a contravariant input, you can't assign the interface covariantly to IFoo<IShape, Base>
, unfortunately.
您需要围绕无法分配到 IFoo< IShape,Base>
或者什么的事实进行编码你可以做的是创建Foo:
You either need to code around the fact you can't assign to IFoo<IShape,Base>
or what you could do is create Foo as:
public class MyFoo:IFoo< Rectangle,Base>
然后在实现中转换为 Rectangle
。主要的是你不能在同一类型参数上同时具有协方差和逆变。
And then cast to Rectangle
inside the implementation. The main thing is you can't have both covariance and contravariance on the same type parameter.
这有意义吗?
这篇关于使用通用接口约束时的协方差/逆差异难题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!