I want to write a CommandProcessor using generics. The idea being that a Command is issued via a single object (the CommandProcessor itself) that then identifies the Command Handlers that process the given command.
However, the following code doesn't compile, and I've not been able to understand why:
class GenericCommandProcessor : ICommandProcessor
{
private readonly IDictionary<Type, IList<ICommandHandler<ICommand>>> _handlers =
new Dictionary<Type, IList<ICommandHandler<ICommand>>>();
public void Register<TCommand>(ICommandHandler<TCommand> handler)
where TCommand : ICommand
{
IList<ICommandHandler<ICommand>> handlers = GetHandlers<TCommand>();
handlers.Add(handler); // <-- This doesn't compile
}
public void Process<TCommand>(TCommand command)
where TCommand : ICommand
{
IList<ICommandHandler<ICommand>> handlers = GetHandlers<TCommand>();
foreach (var commandHandler in handlers)
{
commandHandler.Handle(command);
}
}
private IList<ICommandHandler<ICommand>> GetHandlers<TCommand>()
{
Type commandType = typeof(TCommand);
IList<ICommandHandler<ICommand>> handlers;
if (!_handlers.TryGetValue(commandType, out handlers))
{
handlers = new List<ICommandHandler<ICommand>>();
_handlers.Add(commandType, handlers);
}
return handlers;
}
}
This is the line that doesn't compile:
handlers.Add(handler);
The compiler returns the following error:
cannot convert from 'GenericCommandHandlerTest.ICommandHandler<TCommand>' to 'GenericCommandHandlerTest.ICommandHandler<GenericCommandHandlerTest.ICommand>'
I would expect it to, because Register()
has a generic constraint:
where TCommand : ICommand
I've avoided the issue by resolving the command handler list from IoC (Castle Windsor in my case) in favour of having the dictionary of lists of registered handlers, but I'd love to understand why, at the CLR level, this code doesn't compile. I think I just can't see the wood for the trees...
Many thanks in advance.
Just change your method to this:
public void AddListItem(IListItem listItem)
{
_items.Add(listItem);
}
No need to use generics here.
As others already said: Even without the change, your code compiles, so please update your sample code.
Update after you fixed your example:
You can't add a variable of type ICommandHandler<TCommand>
to a IList<ICommandHandler<ICommand>>
, because ICommandHandler<ICommand>
and ICommandHandler<TCommand>
are two different types, although TCommand
implements ICommand
. If it would work, my first answer would be correct again and you wouldn't need to make your method generic in the first place.
I guess Covariance would be helpful here, but unfortunately it is not supported in that case.
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