Basically, you need to map CommandNExcecutor
type to CommandN
type.
1) Use dictionary. This is easiest way:
private static readonly Dictionary<Type, Type> map = new Dictionary<Type, Type>
{
{ typeof(Command1), typeof(Command1Executor) },
{ typeof(Command2), typeof(Command2Executor) },
...
};
List<CommandResult> Execute(List<CommandBase> commands)
{
return commands
.Select(command =>
{
var executor = Activator.CreateInstance(map[command.GetType], command);
return executor.Execute();
})
.ToList();
}
2) Use metadata (attributes). This fits plugin-based scenarios, when command types can be added dynamically, without rebuilding core functional. It could be your own implementation, or existing DI-container implementation (many of them expose metadata APIs).
[AttributeUsage(AttributeTargets.Class)]
public sealed class CommandExecutorAttribute : Attribute
{
public CommandExecutorAttribute(Type commandType)
{
CommandType = commandType;
}
public Type CommandType { get; }
// ...
}
[CommandExecutor(typeof(Command1))]
public sealed class Command1Executor : ICommandExecutor
{
// ...
}
List<CommandResult> Execute(List<CommandBase> commands)
{
return commands
.Select(command =>
{
// obtain executor types somehow, e.g. using DI-container or
// using reflection;
// inspect custom attribute, which matches command type
var executorType = ....
var executor = Activator.CreateInstance(executorType , command);
return executor.Execute();
})
.ToList();
}
UPDATE.
If you want to avoid reflection, in first case just replace type parameter for value in dictionary to Func<CommandBase, ICommandExecutor>
:
private static readonly Dictionary<Type, Func<ICommandExecutor>> map = new Dictionary<Type, Func<ICommandExecutor>>
{
{ typeof(Command1), command => new Command1Executor(command) },
{ typeof(Command2), command => new Command2Executor(command) },
...
};
This will allow you to create executor through delegate instead of reflection:
var executor = map[command.GetType](command);
The second case can't avoid reflection completely, since you need to get executor types somehow. But it can be leaded to case 1 (with dictionary).
Make the lazy map
:
private static readonly Lazy<Dictionary<Type, ConstructorInfo>> map = ...
Then, on Lazy<T>
initialization, do all reflection work. Since this is static Lazy<T>
, you will do this once per app domain. Calling ConstructorInfo
is fast enough. Hence, you'll get performance hit only once, when handling first command.
Another options (they all assume Lazy<Dictionary>
) for case 2 are:
- instead of reflecting
ConstructorInfo
, build Expression<Func<CommandBase, ICommandExecutor>>
s using ConstructorInfo
, compile them and put delegates into dictionary - this will be the same as delegates for case 1, but with dynamically supported command types;
- use DI-container, which emits IL to construct dependencies (AFAIK, NInject does this);
- emit IL yourself (IMO, this will totally re-invent the wheel).
And finally, solve this the easiest way, then measure performance, then consider more complex way. Avoid premature optimization. I don't know anything about you commands nature, but I suspect, that command execution is much longer, than reflecting something (of course, there's a chance, that I'm wrong).
Hope this helps.