C# 不理解委托的协变和逆变
C# dont understand covariance and contravariance of delegates
很长一段时间以来,我一直在尝试理解与 C# 中的泛型相关的“in”和“out”参数的用处,但我就是无法理解(我知道如何这个问题经常在 Whosebug 上被问到)。我大致了解什么是协变和逆变,只是不知道为什么必须使用“in”和“out”参数。
下面的例子:
public class MainClass {
delegate TOut MyDelegate<TIn, TOut>(TIn input);
public static void Main()
{
// Func Delegate is using "in T, out TResult"
Func<Dog, Mammal> funcDelegate = TestMethod;
// not using "in" or "out" parameters
MyDelegate<Dog, Mammal> myDelegate = TestMethod;
}
static Dog TestMethod(Mammal m) { return new Dog(); }
class Mammal { }
class Dog : Mammal { } }//end of class
当我自己没有“in”和“out”的委托也可以引用协变和逆变的方法时,为什么 Func 委托使用“in”和“out”?
除了 @Pavel Anikhouski comment (linking this 文章)之外,当您尝试下一步时,方差也会发挥作用,例如:
Func<Mammal, Mammal> someFunc = TestMethod;
Func<Dog, Mammal> funcDelegate = someFunc;
MyDelegate<Mammal, Mammal> someDelegate = TestMethod;
MyDelegate<Dog, Mammal> myDelegate = someDelegate; // will not compile unless you will declare MyDelegate<in TIn, TOut>
在问题下的评论之后,Variance in Delegates文档将解释
.NET Framework 3.5 introduced variance support for matching method
signatures with delegate types in all delegates in C#. This means that
you can assign to delegates not only methods that have matching
signatures, but also methods that return more derived types
(covariance) or that accept parameters that have less derived types
(contravariance) than that specified by the delegate type.
因此,尽管委托和 TestMethod
(反向输入参数和 return 类型)的签名不同,但您的分配 MyDelegate<Dog, Mammal> myDelegate = TestMethod;
非常好。
但是,根据 Variance in Generic Type Parameters 部分
,当您在委托之间进行隐式转换时,仍然需要 in
和 out
参数
To enable implicit conversion, you must explicitly declare generic
parameters in a delegate as covariant or contravariant by using the in
or out keyword.
例如以下代码将无法编译
MyDelegate<Dog, Mammal> myDelegate = TestMethod;
MyDelegate<Dog, Dog> anotherDelegate = TestMethod;
myDelegate = anotherDelegate; //error CS0029: Cannot implicitly convert type...
直到您声明 MyDelegate
逆变参数和协变 return 类型
delegate TOut MyDelegate<in TIn, out TOut>(TIn input);
最后一行将编译
很长一段时间以来,我一直在尝试理解与 C# 中的泛型相关的“in”和“out”参数的用处,但我就是无法理解(我知道如何这个问题经常在 Whosebug 上被问到)。我大致了解什么是协变和逆变,只是不知道为什么必须使用“in”和“out”参数。
下面的例子:
public class MainClass {
delegate TOut MyDelegate<TIn, TOut>(TIn input);
public static void Main()
{
// Func Delegate is using "in T, out TResult"
Func<Dog, Mammal> funcDelegate = TestMethod;
// not using "in" or "out" parameters
MyDelegate<Dog, Mammal> myDelegate = TestMethod;
}
static Dog TestMethod(Mammal m) { return new Dog(); }
class Mammal { }
class Dog : Mammal { } }//end of class
当我自己没有“in”和“out”的委托也可以引用协变和逆变的方法时,为什么 Func 委托使用“in”和“out”?
除了 @Pavel Anikhouski comment (linking this 文章)之外,当您尝试下一步时,方差也会发挥作用,例如:
Func<Mammal, Mammal> someFunc = TestMethod;
Func<Dog, Mammal> funcDelegate = someFunc;
MyDelegate<Mammal, Mammal> someDelegate = TestMethod;
MyDelegate<Dog, Mammal> myDelegate = someDelegate; // will not compile unless you will declare MyDelegate<in TIn, TOut>
在问题下的评论之后,Variance in Delegates文档将解释
.NET Framework 3.5 introduced variance support for matching method signatures with delegate types in all delegates in C#. This means that you can assign to delegates not only methods that have matching signatures, but also methods that return more derived types (covariance) or that accept parameters that have less derived types (contravariance) than that specified by the delegate type.
因此,尽管委托和 TestMethod
(反向输入参数和 return 类型)的签名不同,但您的分配 MyDelegate<Dog, Mammal> myDelegate = TestMethod;
非常好。
但是,根据 Variance in Generic Type Parameters 部分
,当您在委托之间进行隐式转换时,仍然需要in
和 out
参数
To enable implicit conversion, you must explicitly declare generic parameters in a delegate as covariant or contravariant by using the in or out keyword.
例如以下代码将无法编译
MyDelegate<Dog, Mammal> myDelegate = TestMethod;
MyDelegate<Dog, Dog> anotherDelegate = TestMethod;
myDelegate = anotherDelegate; //error CS0029: Cannot implicitly convert type...
直到您声明 MyDelegate
逆变参数和协变 return 类型
delegate TOut MyDelegate<in TIn, out TOut>(TIn input);
最后一行将编译