I\'m stuck, why isn\'t this working:
var childAction = new Action(blabla);
Action upperAction = (Action
This is contravariance. This isn't working, because if this will be possible, you could write something like this:
interface IDomainCommand { }
class CancelCommand : IDomainCommand { }
class AcceptCommand : IDomainCommand { }
Action<CancelCommand> a1 = c => { };
Action<IDomainCommand> a2 = a1;
var acceptCommand = new AcceptCommand();
a2(acceptCommand); // what???
a2
points to a1
, and a1 can't accept AcceptCommand
argument, because it is not a CancelCommand
.
Your forgetting how these delegates are being used
var childAction = new Action<CancelCommand>(blabla);
Action<IDomainCommand> upperAction = (Action<IDomainCommand>) childAction;
means that upperAction
will at some point in the future be called, passing some form of an IDomainCommand
object. You are giving it an function which can only handle CancelCommand
objects. But there are (probably) other classes which implement IDomainCommand
, and upperAction
could potenially be called with any of them.
Hang on, why do you want this to work?
Your childAction
is something that accepts a CancelCommand
and does something with it.
But upperAction
could be invoked on any IDomainCommand
, not just a CancelCommand
. Supposing the above compiled; what should then happen when I do
upperAction(new EditCommand());
where class EditCommand : IDomainCommand
?
If you attempt an assignment the other way round:
var upperAction = new Action<IDomainCommand>(idc => { });
Action<CancelCommand> childAction = upperAction;
it works and you don't even need a cast. Any Action<IDomainCommand>
counts as an Action<CancelCommand>
.
The type parameter of Action
is contravariant: you can assign an Action<object>
to an Action<string>
because obviously a method that can work on any object can also work on a string.
What you do here is trying to bill a method that works on a CancelCommand
(derived type) as a method that works on any IDomainCommand
(base type). This is logically wrong, so the compiler doesn't let you do it -- if it did, you could just invoke upperAction
passing it a DifferentTypeOfDomainCommand
.