为简化起见,假设我有一个父类和一个子类:
public class MyParent { }
public class MyChild : MyParent { }
这两个函数带有一些代码:
public void DoSomethingBy_MyChild(MyChild myChild) { //code }
public void DoSomethingBy_MyParent(MyParent myParent) { //code }
但是,当我尝试使用带有Action<MyChild>
参数的DoSomethingBy_MyParent
的{{1}}委托进行单元测试时,编译器会说:
错误CS1503参数1:无法从“ MyParent”转换为“ MyChild”。
MyParent
答案 0 :(得分:3)
来自Using Variance in Delegates (C#):
当您将方法分配给委托时, covariance 和 contravariance 可以灵活地将委托类型与方法签名进行匹配。协方差允许方法具有比委托中定义的返回类型更多的返回类型。逆变性允许一种方法,该方法具有比委托类型中的参数类型更少的参数类型。
可以将DoSomethingBy_MyParent
分配给processor
(由于MyParent
比MyChild
派生的,所以是{em> contravariant 分配),这是因为是MyChild
,根据定义也是MyParent
:
Action<MyChild> processor;
processor = DoSomethingBy_MyParent;
但是,当您尝试将MyParent
传递到processor
时会发生什么情况
Action<MyChild> processor;
processor(new MyParent());
这不好,因为processor
要求将MyChild
传递给它-不能相反地调用。分配了DoSomethingBy_MyParent
都没关系-processor
被声明为Action<MyChild>
,因此它必须接收MyChild
的实例或更衍生的类型。
换句话说,您有
public void DoSomethingBy_MyChild(MyChild myChild) { //code }
,您将无法像这样调用它:
DoSomethingBy_MyChild(new Parent());
因为方法调用的工作是协变的(您可以传入派生类型更大的实例),而不是协变的(您不能传入派生类型较少的实例)。
答案 1 :(得分:2)
这可能会帮助Action delegates, generics, covariance and contravariance
基本上,一切都很好。 Action<T>
是反变量,因此可以将DoSomethingBy_MyParent
分配给Action<MyChild> processor
。这是矛盾的。
但是由于processor
的类型为Action<MyChild>
,因此您无法使用MyParent
实例来调用它。