在我们的代码中尝试了类似的东西,但它失败了:
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 { }
最后两个案例给出了这个错误:
无法将
System.Func<Employee, Employee>
类型隐式转换为System.Func<Person, Employee>
。存在显式转换(您是否错过了演员?)
知道为什么吗?
答案 0 :(得分:12)
如果您查看Func<T, TResult>
的签名,您会看到输入参数(在这种情况下为T
)是逆变,并且返回类型({ {1}})是协变
TResult
逆变法基本上是关于能够将“更大”类型传递给期望“更小”类型的方法,其中协方差恰恰相反。
Eric Lippert提出这个beautifully and elegantly (emphasis mine):
如果使用引用构造,泛型类型I 协变(在T中) 类型参数保留赋值兼容性的方向。它 是逆变(在T中),如果反转分配方向 兼容性即可。如果既不又不变。就此而言,我们 简单地说是一个需要T的投影 并产生我是一个协变/逆变/不变投影。
答案 1 :(得分:2)
因为<img src="http://example.com/cat.png"
<img src="http://example.com/dog.png"
<img src="http://example.com/rat.png"
定义为
Func<T, TResult>
正如你所看到的,第二个参数(public delegate TResult Func<in T, out TResult>(T arg);
)确实是一个协变,但第一个参数(TResult
,它是函数的输入)实际上是一个逆变(你只能用不太衍生的东西喂它。
T
很好,因为它与签名匹配,而Func<Employee, Person>
失败,因为它不是。
请参阅MSDN
答案 2 :(得分:0)
好的,我想我现在明白了:
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;} }
答案 3 :(得分:-3)
Person
不是Employee
Func<Employee, xxx>
和Func<Person, xxx>