c#.net 4.0 Covariant vs Contravariant

时间:2017-06-07 19:45:44

标签: c# .net .net-4.0 contravariance covariant

在尝试使用Contravariance时,我试图让一些工作和下面的事情挣扎。我的理解是Covariance是你可以从基类型返回派生类型的地方。逆变量是您可以将派生类型从基类型作为参数传递到类中的地方。

所以我有以下界面(逆变):

public interface IBase<in T> where T: BaseModel
{
        void Process(T model);
}

然后我有一个抽象类

public abstract class Base<T>: IBase<T> where T: BaseModel
{
    public virtual void Process(T model)
    {
       // throw new System.NotImplementedException();
    }
}

和另一个具体的课程

public class Parent: Base<ParentModel>
{
    public override void Process(ParentModel model)
    {
        // throw new System.NotImplementedException();
    }
}

考虑到泛型类型只用作输入而不是返回类型,我不明白为什么我不能执行以下操作:

IBase<BaseModel> baseContravariant = new  Parent();
// This doesn't compile. I will eventually have a list of IBase<BaseMode> to which I'd like to pass in different parent instances.

我有另一个使用协方差的例子,它在下面并且工作正常。

public interface IBase<out T> where T : BaseModel, new()
{
    T ProcessAndGet();
}

摘要

public abstract class Base<T>: IBase<T> where T: BaseModel, new()
{
    public virtual T ProcessAndGet()
    {
        var result = new T() as BaseModel;

        // More shizzle here
        return (T)result;
    }
}

混凝土

public class Parent : Base<ParentModel>
{ 
    public override ParentModel ProcessAndGet()
    {
        var x = base.ProcessAndGet();
        return x;
    }
}

现在我可以做到

IBase<BaseModel> baseInstance = new Base<BaseModel>();
IBase<BaseModel> derived = new Parent();
baseInstance = derived;

以上示例还有更多代码,但我已将其删除以便于阅读(希望如此!): - )

1 个答案:

答案 0 :(得分:0)

在这种情况下,逆变量意味着您需要传递具有指定类型的类型或“更专业化”的类型(=&gt;派生自基本类型)。

由于您的第一个示例中的Parent实现只能处理ParentModel,因此传入BaseModel实例无效。尝试做new Parent().Process(new BaseModel())也不会编译。因此将其强制转换为IBase<BaseModel>无效。 (假设ParentModelBaseModel)的子类。

在这种情况下,通过认为IBase<in T>“消耗T”,反演模型更容易推理。因此,IBase<ParentModel>“消耗ParentModel s”。这意味着它只能传递ParentModel实例的值,或者可以被视为一个(实际上只是子类)。

在您的第二个示例中,您使用的是<out T>,这是“协变”。这可以描述为“它产生T的实例”。因此,“生成”ParentModel的类自动也是BaseModel的“生产者”:由于ParentModel可以加载到BaseModelIBase<ParentModel>可以也可以转换为IBase<BaseModel>