在尝试使用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;
以上示例还有更多代码,但我已将其删除以便于阅读(希望如此!): - )
答案 0 :(得分:0)
在这种情况下,逆变量意味着您需要传递具有指定类型的类型或“更专业化”的类型(=&gt;派生自基本类型)。
由于您的第一个示例中的Parent
实现只能处理ParentModel
,因此传入BaseModel
实例无效。尝试做new Parent().Process(new BaseModel())
也不会编译。因此将其强制转换为IBase<BaseModel>
无效。 (假设ParentModel
是BaseModel
)的子类。
在这种情况下,通过认为IBase<in T>
“消耗T”,反演模型更容易推理。因此,IBase<ParentModel>
“消耗ParentModel
s”。这意味着它只能传递ParentModel
实例的值,或者可以被视为一个(实际上只是子类)。
在您的第二个示例中,您使用的是<out T>
,这是“协变”。这可以描述为“它产生T
的实例”。因此,“生成”ParentModel
的类自动也是BaseModel
的“生产者”:由于ParentModel
可以加载到BaseModel
,IBase<ParentModel>
可以也可以转换为IBase<BaseModel>
。