3
    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();
        }
    }

鉴于上面的代码,编译器无法确定如何将类型分配MyFooIFoo<IShape, Base>,大概是因为U设置为 out 意味着它可以接受更少的派生。但是,Derived是 比 更派生Base,因此会产生编译器错误。

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

虽然U用作参数,但在尝试将其分配给通用接口时它也是一个输出,但我无法在out此处使用关键字。我们如何解决这个问题?

4

2 回答 2

1

您的 IFoo 接口在这种用法中似乎是错误的,应该是:

public interface IFoo<out T, **out** U>

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

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

IFoo<IShape, Base> hmm = new MyFoo();

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

更新:在您发表评论后,我发现最大的困境是您希望它既进又出,这实际上是不可能的因为它是一个逆变输入IFoo<IShape, Base>,不幸的是,您不能将接口协变地分配给 。

您要么需要围绕您无法分配的事实进行编码,要么IFoo<IShape,Base>您可以做的是将 Foo 创建为:

public class MyFoo : IFoo<Rectangle, Base>

然后投到Rectangle里面执行。主要的是你不能在同一个类型参数上同时拥有协变和逆变。

这有意义吗?

于 2011-05-25T15:46:55.127 回答
0

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

于 2011-05-25T19:39:09.957 回答