0

使用逆变器时,我正在尝试使以下内容正常工作和挣扎。我的理解是协方差是您可以从基类型返回派生类型的地方。逆变是您可以将派生类型从基类型作为参数传递给类的地方。

所以我有以下接口(逆变):

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;

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

4

1 回答 1

0

在这种情况下,逆变意味着您需要传入指定类型或“更专业”的类型(=> 从基本类型派生)。

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

在这种情况下,逆变模型更容易通过认为IBase<in T>“消耗 T”来推理。所以一个IBase<ParentModel>“消耗ParentModels”。这意味着它只能传递作为实例ParentModel或可以被视为一个(实际上只有子类)的值。

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

于 2017-06-07T19:54:06.080 回答