Enumeration with Generic Interface
Problem
I have commands to execute. Commands are plain C# classes with some data.
var commands = new List<ICommand>
{
new Command1("A"),
new Command1("B"),
new Command2(20, 30)
};
And I want to make command-specific handlers.
public class Command1Handler : ICommandHandler<Command1>
{
public bool CanHandle(ICommand command)
{
return command is TCommand; // this is always the same for all command handlers.
}
public void Execute(Command1 command)
{
// TODO: execute the command. I want to accept Command1, not ICommand.
}
}
And finally, I want to loop through commands and call corresponding commandHandlers.
var commandHandlers = new List<ICommandHandler>()
{
new Command1Handler(),
new Command2Handler()
};
foreach (var command in commands)
{
var handler = commandHandlers.Single(x => x.CanHandle(command));
handler.Execute(command);
}
C# does not allow such usage, since ICommandHandler<>
cannot be used without <>
. How do we solve this problem?
Solution
Define ICommandHandler
as command-type-agnostic.
public interface ICommandHandler
{
void Execute(ICommand command);
bool CanHandle(ICommand command);
}
Define CommandHandlerBase
as generic class that accepts command-type T
. It implements ICommandHandler
, and it requires its child to implement abstract Execute(T command)
.
public abstract class CommandHandlerBase<T>: ICommandHandler where T: ICommand
{
public bool CanHandle(ICommand command)
{
return command is T;
}
protected abstract void Execute(T command);
public void Execute(ICommand command)
{
Execute((T)command);
}
}
Now command handler looks like:
public class Command1Handler : CommandHandlerBase<Command1>
{
protected override void Execute(Command1 command)
{
// TODO: execute the command
}
}
Note that Command1Handler
’s Execute()
receives Command1
, not ICommand
.
Bonus: Command1Handler does not worry about CanHandle(), since by declaring CommandHandlerBase<Command1>
I already said I can handle Command1
only.