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>
. 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
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):
A generic type I is covariant (in T) if construction with reference type arguments preserves the direction of assignment compatibility. It is contravariant (in T) if it reverses the direction of assignment compatibility. 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.
Because Func<T, TResult>
is a defined as
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).
Func<Employee, Person>
is fine because it sill matches the signature, while Func<Person, Person>
fails because it isn't.
See MSDN
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With