委托的逆变导致 "Cannot convert from ... to ..." 的错误
Contravariance of delegate resulting in error of "Cannot convert from ... to ..."
为了简化,假设我有一个 parent 和一个 child class:
public class MyParent { }
public class MyChild : MyParent { }
这两个函数带有一些代码:
public void DoSomethingBy_MyChild(MyChild myChild) { //code }
public void DoSomethingBy_MyParent(MyParent myParent) { //code }
但是当我尝试使用 DoSomethingBy_MyParent
和 MyParent
参数对 Action<MyChild>
委托进行单元测试时,编译器说:
Error CS1503 Argument 1: cannot convert from 'MyParent' to 'MyChild'.
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
}
这可能会有所帮助 Action delegates, generics, covariance and contravariance
基本上,一切都很好。 Action<T>
是逆变的,因此您可以将 DoSomethingBy_MyParent
分配给 Action<MyChild> processor
。这就是逆变。
但是因为 processor
是类型 Action<MyChild>
你不能用 MyParent
实例调用它。
来自 Using Variance in Delegates (C#):
When you assign a method to a delegate, covariance and contravariance provide flexibility for matching a delegate type with a method signature. Covariance permits a method to have return type that is more derived than that defined in the delegate. Contravariance permits a method that has parameter types that are less derived than those in the delegate type.
可以将 DoSomethingBy_MyParent
分配给 processor
( 逆变 分配,因为 MyParent
比 MyChild
) 因为根据定义,任何 MyChild
也是 MyParent
:
Action<MyChild> processor;
processor = DoSomethingBy_MyParent;
但是,当您尝试将 MyParent
传递给 processor
时,实际上发生的情况是
Action<MyChild> processor;
processor(new MyParent());
这不好,因为 processor
需要将 MyChild
传递给它 - 它不能被 调用 逆变。您已将 DoSomethingBy_MyParent
分配给它并不重要 - processor
被声明为 Action<MyChild>
因此它 必须 接收 [= 的实例17=] 或更派生的类型。
换句话说,你有
public void DoSomethingBy_MyChild(MyChild myChild) { //code }
而且您不会期望能够像这样调用它:
DoSomethingBy_MyChild(new Parent());
因为方法调用是协变的(您可以传入派生程度更高的类型的实例),而不是逆变的(您不能传入派生程度较低的类型的实例)。
为了简化,假设我有一个 parent 和一个 child class:
public class MyParent { }
public class MyChild : MyParent { }
这两个函数带有一些代码:
public void DoSomethingBy_MyChild(MyChild myChild) { //code }
public void DoSomethingBy_MyParent(MyParent myParent) { //code }
但是当我尝试使用 DoSomethingBy_MyParent
和 MyParent
参数对 Action<MyChild>
委托进行单元测试时,编译器说:
Error CS1503 Argument 1: cannot convert from 'MyParent' to 'MyChild'.
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
}
这可能会有所帮助 Action delegates, generics, covariance and contravariance
基本上,一切都很好。 Action<T>
是逆变的,因此您可以将 DoSomethingBy_MyParent
分配给 Action<MyChild> processor
。这就是逆变。
但是因为 processor
是类型 Action<MyChild>
你不能用 MyParent
实例调用它。
来自 Using Variance in Delegates (C#):
When you assign a method to a delegate, covariance and contravariance provide flexibility for matching a delegate type with a method signature. Covariance permits a method to have return type that is more derived than that defined in the delegate. Contravariance permits a method that has parameter types that are less derived than those in the delegate type.
可以将 DoSomethingBy_MyParent
分配给 processor
( 逆变 分配,因为 MyParent
比 MyChild
) 因为根据定义,任何 MyChild
也是 MyParent
:
Action<MyChild> processor;
processor = DoSomethingBy_MyParent;
但是,当您尝试将 MyParent
传递给 processor
时,实际上发生的情况是
Action<MyChild> processor;
processor(new MyParent());
这不好,因为 processor
需要将 MyChild
传递给它 - 它不能被 调用 逆变。您已将 DoSomethingBy_MyParent
分配给它并不重要 - processor
被声明为 Action<MyChild>
因此它 必须 接收 [= 的实例17=] 或更派生的类型。
换句话说,你有
public void DoSomethingBy_MyChild(MyChild myChild) { //code }
而且您不会期望能够像这样调用它:
DoSomethingBy_MyChild(new Parent());
因为方法调用是协变的(您可以传入派生程度更高的类型的实例),而不是逆变的(您不能传入派生程度较低的类型的实例)。