[英]Func variance with multiple parameters
Tried to something like this in our code but it fails: 在我们的代码中尝试了类似的东西,但它失败了:
Func<Employee, Employee> _myFunc;
void Main()
{
Func<Employee, Employee> test1 = _myFunc;//Ok
Func<Employee, Person> test2 = _myFunc;//Ok
Func<Person, Employee> test3 = _myFunc;//Fails
Func<Person, Person> test4 = _myFunc;//Fails
}
public class Person { }
public class Employee : Person { }
The last two cases give this error: 最后两个案例给出了这个错误:
Cannot implicitly convert type
System.Func<Employee, Employee>
toSystem.Func<Person, Employee>
. 无法将System.Func<Employee, Employee>
类型隐式转换为System.Func<Person, Employee>
。 An explicit conversion exists (are you missing a cast?) 存在显式转换(您是否错过了演员?)
Any idea why? 知道为什么吗?
If you look at the signature for Func<T, TResult>
, you'll see that the input parameters ( T
in this case) are contravariant , and the return type ( TResult
) is covariant 如果你看一下Func<T, TResult>
的签名,你会看到输入参数(在这种情况下为T
)是逆变的 ,返回类型( TResult
)是协变的
public delegate TResult Func<in T, out TResult>(T arg);
Contravariance is basically about being able to pass a "bigger" type to a method expecting a "smaller" type, where covariance is exactly the opposite. 逆变量基本上是关于能够将“更大”类型传递给期望“更小”类型的方法,其中协方差恰恰相反。
Eric Lippert puts this beautifully and elegantly (emphasis mine) : 埃里克·利珀特( Eric Lippert )非常优雅(强调我的) :
A generic type I is covariant (in T) if construction with reference type arguments preserves the direction of assignment compatibility . 如果具有引用类型参数的构造保留赋值兼容性的方向,则泛型类型I是协变的 (在T中)。 It is contravariant (in T) if it reverses the direction of assignment compatibility . 如果它颠倒了赋值兼容性的方向,则它是逆变的 (在T中)。 And it is invariant if it does neither . 如果两者都没有 ,那就是不变的 。 And by that, we simply are saying in a concise way that the projection which takes a T and produces I is a covariant/contravariant/invariant projection. 通过这种方式,我们只是简单地说,采用T并产生I的投影是协变/逆变/不变投影。
Because Func<T, TResult>
is a defined as 因为Func<T, TResult>
被定义为
public delegate TResult Func<in T, out TResult>(T arg);
As you can see, the second parameter ( TResult
) is indeed a covariant, but the first parameter ( T
, which is the input of the function) is actually a contravariant (you can only feed it with something that is less-derived). 正如你所看到的,第二个参数( TResult
)确实是一个协变,但第一个参数( T
,它是函数的输入)实际上是一个逆变(你只能用不太衍生的东西来提供它)。
Func<Employee, Person>
is fine because it sill matches the signature, while Func<Person, Person>
fails because it isn't. Func<Employee, Person>
很好,因为它与签名匹配,而Func<Person, Person>
失败,因为它不是。
Ok, I think I understand it now: 好的,我想我现在明白了:
void Main()
{
Func<Employee, Employee> getEmployeesBoss = (Employee employee) => {return employee.Boss;};
//This works as it expects a Person to be returned and employee.Boss is a person.
Func<Employee, Person> getEmployeesBoss1 = getEmployeesBoss;
//This fails as I could pass a non Employee person to this func which would not work.
Func<Person, Employee> getEmployeesBoss2 = getEmployeesBoss;
}
class Person {}
class Employee : Person { public Employee Boss{get;set;} }
A Person
is not an Employee
一个Person
不是Employee
There is no cast possible between Func<Employee, xxx>
and Func<Person, xxx>
Func<Employee, xxx>
和Func<Person, xxx>
之间没有可能的Func<Employee, xxx>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.