Why C# cannot cast implicitly an Action<T> Where T : BaseType to Action<BaseType>

I try to cast an Action to is constraint type. Why C# cannot cast It ?

If I force cast the return is null

private Action<BaseObject> MyAction { get; set; }

//Cannot implicitly cast
internal void SetMyAction<TModel>(Action<TModel> action) where TModel : BaseObject
{
    MyAction = action;
}

//MyAction return null
internal void SetMyAction<TModel>(Action<TModel> action) where TModel : BaseObject
{
    MyAction = (Action<TModel>)action;
}
Jon Skeet
people
quotationmark

Not every Action<TModel> is an Action<BaseObject>. Let's look at a concrete example: Action<string> and Action<object>.

An Action<object> delegate can take any object reference as a parameter. It's perfectly valid to write action(new object()).

Now think about an Action<string> - it can only take a string reference. You apparently expect the following code to compile - how would you expect it to behave at execution time?

Action<string> printLength = text => Console.WriteLine(text.Length);
Action<object> action = printLength; // This isn't actually valid
action(new object());

Basically, Action<T> is contravariant in T, not covariant. So there is an implicit conversion from Action<object> to Action<string>, but not vice versa.

Applying that to your specific case, imagine that I had:

Action<DerivedObject1> x = do1 => Console.WriteLine(do1.SomeProperty);
SetMyAction<DerivedObject1>(x);

// Presumably there's *something* to invoke the action...
InvokeMyAction(new DerivedObject2());

What would you expect to happen?

people

See more on this question at Stackoverflow