简体   繁体   English

具有多个参数的Func方差

[英]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> to System.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>失败,因为它不是。

See MSDN 请参阅MSDN

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM