C# 使用通用接口约束时的协方差/反方差难题 公共接口IShape{} 公共类矩形:IShape{} 公共类基类{} 派生的公共类:基类{} 公共接口IFoo T:IShape在哪里 你在哪里:基地 { T转换(U-myType); } 公共类MyFoo:IFoo { 公共矩形转换(派生myType) { 抛出新的NotImplementedException(); } } 班级计划 { 静态void Main(字符串[]参数) { IFoo hmm=new MyFoo(); } }

C# 使用通用接口约束时的协方差/反方差难题 公共接口IShape{} 公共类矩形:IShape{} 公共类基类{} 派生的公共类:基类{} 公共接口IFoo T:IShape在哪里 你在哪里:基地 { T转换(U-myType); } 公共类MyFoo:IFoo { 公共矩形转换(派生myType) { 抛出新的NotImplementedException(); } } 班级计划 { 静态void Main(字符串[]参数) { IFoo hmm=new MyFoo(); } },c#,generics,interface,covariance,contravariance,C#,Generics,Interface,Covariance,Contravariance,给定上述代码,编译器无法确定如何将类型MyFoo分配给IFoo,可能是因为U被设置为out,这意味着它可以接受较少的派生。但是,Derived比Base派生得更多,因此会生成编译器错误 这个示例是人为设计的,但是我们正在处理的实现是一个从工厂返回MyFoo的实现 虽然U用作参数,但在尝试将其分配给通用接口时,它也是一个输出,但我无法在此处使用out关键字。我们如何解决这个问题?您的IFoo界面在这种用法中似乎是错误的,应该是: public interface IShape{}

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

这个示例是人为设计的,但是我们正在处理的实现是一个从工厂返回
MyFoo
的实现


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

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

    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();
        }
    }
所以它不能进行隐式转换。如果确实希望能够隐式扩展此接口,则第二个类型参数应该是
out
,而不是
in

更新:在您的评论之后,我发现最大的难题是您希望它同时处于输入和输出状态,这实际上是不可能的,因为它是一个逆变输入,不幸的是,您无法将接口协变地分配给
IFoo

您要么需要围绕无法分配给
IFoo
的事实进行编码,要么可以将Foo创建为:

公共类MyFoo:IFoo

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


这有意义吗?

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

确实,这是有意义的。然而,由于U是一种方法的输入,因此将其更改为out收益率;无效差异:类型参数“U”在“ConsoleApplication3.IFoo.Convert(U)”上必须相反有效U’是协变的。这一点很好,那么答案就是你不能这么做。你不能让一个类型同时是协变和逆变的。因此,您必须将hmm指定为IFOO,您的意思是在实现内部将其转换为
派生的
?到目前为止,您只陈述了事实。你有这个代码,你有问题,你得到一个编译器错误;听起来我每天都在工作!你有什么问题想问我们吗?呵呵,说得好:)我想我想要一些变通的想法,但没有明确要求:当你说“…可能无法对基地做任何有用的事情”,接口有一个约束,即
U
必须至少是ttype
Base
,因此我希望实现接口IFoo的任何东西都知道如何处理
Base
。可以接受基类型作为参数的东西可以接受派生类型,但反过来则不正确。一些知道如何处理每一辆丰田车的人可能不知道如何处理福特金牛,即使丰田和福特金牛都来自汽车。MyFoo类接受派生类型的对象。它还可以接受子派生类型的对象。它无法处理Base类型的对象。
public interface IFoo<out T, **out** U>
IFoo<IShape, Base> hmm = new MyFoo();