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

问题描述 投票:1回答:2

为了简化,假设我有父类和子类:

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 param对MyParent委托进行单元测试时,编译器说:

错误CS1503参数1:无法从“父”转换为“我的孩子”。

public void UnitTest()
{            
    Action<MyChild> processor;
    processor = DoSomethingBy_MyChild;
    processor(new MyChild());             //OK

    processor = DoSomethingBy_MyParent; 
    processor(new MyChild());             //OK

    processor = DoSomethingBy_MyParent;
    processor(new MyParent());            //Error
}
c# delegates contravariance
2个回答
3
投票

来自Using Variance in Delegates (C#)

将方法分配给委托时,协方差和逆变提供了将委托类型与方法签名匹配的灵活性。协方差允许方法具有比委托中定义的更多派生的返回类型。 Contravariance允许一种方法,其参数类型的派生类型少于委托类型中的参数类型。


DoSomethingBy_MyParent分配给processor(由于MyParentMyChild更少衍生而导致的逆变量赋值)是正常的,因为根据定义,任何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());

因为方法调用协同工作(您可以传入更多派生类型的实例),而不是相反(您不能传入较少派生类型的实例)。


2
投票

这可能有助于Action delegates, generics, covariance and contravariance

基本上,一切都很好。 Action<T>是逆变的,所以你可以将DoSomethingBy_MyParent分配给Action<MyChild> processor。这是相反的。

但由于processorAction<MyChild>类型,你不能用MyParent实例调用它。

© www.soinside.com 2019 - 2024. All rights reserved.