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

||
    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
比than5ѭ派生更多,因此会产生编译器错误。 这个例子是人为设计的,但是我们要处理的实现是从工厂返回
MyFoo
的实现。 尽管将ѭ3as用作参数,但是当尝试将其分配给通用接口时它也是输出,但是在这里我无法使用
out
关键字。我们如何解决这个问题?     
已邀请:
您的IFoo接口在这种用法中似乎是错误的,应该是:
public interface IFoo<out T, **out** U>
U
被淘汰。请记住,“ 8”泛型类型参数意味着它可以变化“向外”。也就是说,可以将类型隐式扩展为更大的类型。但是,“ 12”表示您可以隐式地将“向内”类型缩小为更具体的类型。当然,这些只是粗略的类比。 因此,在分配
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。但是,某些可以将“派生”转换为“矩形”的事物可能无法对Base执行任何有用的操作。您正确地确定了第二个参数的协方差说明符需要为“ in”,但是随后尝试以与实际支持相反的方式使用协方差。     

要回复问题请先登录注册