Reputation: 37113
I have an interface IGenericOrder
as follows:
using System;
using System.Linq.Expressions;
namespace MyNamespace
{
interface IGenericOrder<T> where T : new()
{
Func<T, int> GetStatement(string name);
}
public class GenericOrder<T> : IGenericOrder<T> where T : new()
{
public Func<T, int> GetStatement(string name)
{
return (T) => 4;
}
}
}
Now when I create an instance of that class and cast it back to IGenericOrder<object>
var sorter = (IGenericOrder<object>) new GenericOrder<Foo>();
I get Exception:
InvalidCastException: The instance of type
GenericOrder<Foo>
cannot be cast toIGenericOrder<object>
Which seems clear as the Interface IGenericOrder
is not covariant. However if I make the interface covariant (interface IGenericOrder<out T>
) I get a compiler-error:
Invalid variance: The type parameter 'T' must be contravariantly valid on
IGenericOrder<T>.GetStatement(string)
. 'T' is covariant.
As I read from here covariance can only used when
[the generic type parameter] is used only as a method return type and is not used as a type of formal method parameters.
Does this mean I cannot use co-/contravariance for methods that themselfes return generic instances?
I am using .Net 4.5
Upvotes: 1
Views: 651
Reputation: 727077
To understand what is going on look at the definition of Func<T,TResult>
delegate:
public delegate TResult Func<in T, out TResult>(
T arg
)
As you can see, its first type parameter T
is an in
parameter. Therefore, you cannot use an out
parameter as Func
's first type argument. The second type parameter TResult
is out
, so using T
as TResult
would work:
interface IGenericOrder<out T> where T : new() {
Func<int,T> GetStatement(string name);
}
public class GenericOrder<T> : IGenericOrder<T> where T : new() {
public Func<int,T> GetStatement(string name) {
return (x) => default(T);
}
}
Upvotes: 2
Reputation: 38010
You are using T
as the first type parameter of Func
, so the only valid mode is contravariance because the T
represents the type of the function's parameter. What you are trying to achieve with your cast is unsafe: you are saying "Here's a function which takes a Foo
as a parameter. Please treat this as a function which takes any object
as a parameter." If instead you had a Func<int, T>
, you could use covariance, because a function that returns a Foo
can also be viewed as a function that returns an object
.
Upvotes: 1