基本上,您需要将CommandNExcecutor
类型映射到CommandN
类型。
1)使用字典。这是最简单的方法:
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)使用元数据(属性)。这适合基于插件的场景,可以在不重建核心功能的情况下动态添加命令类型。它可能是您自己的实现,或者是现有的DI容器实现(其中许多实现了元数据API)。
[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。
如果你想避免反射,在第一种情况下只需更换类型参数在字典中的价值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) },
...
};
这将允许您通过委派,而不是反射创建执行人:
var executor = map[command.GetType](command);
第二种情况不能完全避免反射,因为您需要以某种方式获得执行程序类型。但它可以引导到案例1(用字典)。
让懒惰map
:
private static readonly Lazy<Dictionary<Type, ConstructorInfo>> map = ...
然后,在Lazy<T>
初始化,完成所有工作反思。由于这是static Lazy<T>
,您将为每个应用域执行一次此操作。拨打ConstructorInfo
速度够快。因此,在处理第一条命令时,您只会获得一次性能。
另一个选项(他们都承担Lazy<Dictionary>
)的情况下,2:
- ,而不是反映
ConstructorInfo
,使用ConstructorInfo
打造Expression<Func<CommandBase, ICommandExecutor>>
S,编译并把代表到字典 - 这将是同代表们情况1,但具有动态支持的命令类型;
- 使用DI容器,它发射IL来构造依赖关系(AFAIK,NInject这样做);
- 自己发射IL(IMO,这将完全重新发明车轮)。
最后,解决这个问题最简单的方法,然后衡量性能,然后考虑更复杂的方式。避免过早优化。我对你对自然的命令一无所知,但我怀疑,这个命令的执行时间比反映某些东西的时间要长(当然,这有可能是我错了)。
希望这会有所帮助。
把所有的命令执行者(或functons创建它们)在字典中,由命令类型键。这样你就不需要连锁。 – Evk