代表的矛盾导致错误“无法从...转换为...”

时间:2019-04-29 05:06:35

标签: c# delegates contravariance

为简化起见,假设我有一个父类和一个子类:

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

2 个答案:

答案 0 :(得分:3)

来自Using Variance in Delegates (C#)

  

当您将方法分配给委托时, covariance contravariance 可以灵活地将委托类型与方法签名进行匹配。协方差允许方法具有比委托中定义的返回类型更多的返回类型。逆变性允许一种方法,该方法具有比委托类型中的参数类型更少的参数类型。


可以将DoSomethingBy_MyParent分配给processor(由于MyParentMyChild派生的,所以是{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实例来调用它。