Func rejection with multiple parameters

Tried 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:

It is not possible to implicitly convert the type System.Func<Employee, Employee> to System.Func<Person, Employee> . Explicit conversion exists (are you skipping listing?)

Any idea why?

+5
source share
4 answers

If you look at the signature for Func<T, TResult> , you will see that the input parameters ( T in this case) are contravariant, and the return type ( TResult ) is covariant

 public delegate TResult Func<in T, out TResult>(T arg); 

The contravariance basically lies in the ability to pass the "larger" type to a method that expects a "smaller" type, where covariance is exactly the opposite.

Eric Lippert does it beautifully and elegantly (my attention) :

Generic type I covariant (in T), if the construction with reference type arguments retain the direction of assignment compatibility . This is contravariant (in T) if it changes the direction of assignment compatibility . And this is invariant if it does not . And thus, we simply say briefly that the projection that takes T and gives me is a covariant / contravariant / invariant projector.

+12
source

Because Func<T, TResult> is defined as

 public delegate TResult Func<in T, out TResult>(T arg); 

As you can see, the second parameter ( TResult ) is indeed covariant, but the first parameter ( T , which is the input of the function) is actually contravariant (you can only feed it which is less pronounced).

Func<Employee, Person> excellent because the window sill matches the signature, and Func<Person, Person> fails because it is not.

See MSDN

+2
source

Well, I think I understand this 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;} } 
0
source

A Person not an Employee

Between Func<Employee, xxx> and Func<Person, xxx>

there is no throwing effect.
-3
source

Source: https://habr.com/ru/post/1245071/


All Articles