通用命令处理程序的简单注入器用法
接口,命令和命令处理程序按照Simpleinjector wiki中的说明进行设置。
public interface ICommand { string Name { get; set; } } public class Command1 : ICommand { public string Name { get; set; } } public class Command2 : ICommand { public string Name { get; set; } } public interface ICommandHandler { void Execute(TCommand Command); } public class Command1Handler : ICommandHandler { public void Execute(Command1 Command) { Console.WriteLine(Command.Name); } } public class Command2Handler : ICommandHandler { public void Execute(Command2 Command) { Console.WriteLine(Command.Name + "Hello"); } }
装饰:
public class CommandDecorator : ICommandHandler { private readonly ICommandHandler _handler; public CommandDecorator(ICommandHandler handler) { this._handler = handler; } public void Execute(TCommand command) { this._handler.Execute(command); } }
示例程序
public class Program { static void Main(string[] args) { Container container = new Container(); //registering container.RegisterAll(typeof(Command1), typeof(Command2)); container.RegisterManyForOpenGeneric( typeof(ICommandHandler), typeof(ICommandHandler).Assembly); container.RegisterDecorator(typeof(ICommandHandler), typeof(CommandDecorator)); container.Verify(); // sample test command ICommand testcommand = new Command2(); testcommand.Name = "command 1"; var type = typeof(ICommandHandler).MakeGenericType(testcommand.GetType()); dynamic instance = container.GetInstance(type); instance.Execute((dynamic)testcommand); } }
这是获取在运行时处理命令的正确处理程序的正确方法。 这是一个示例,在实际应用程序中,命令将发布到队列,服务将读取命令并对其进行处理。 我想装饰器必须用于此但却无法使其工作。 请提出更好的选择。
您的命令( Command1
和Command2
)不是服务:它们不应该注册。 它们是您通过服务(命令处理程序)传递的运行时数据(消息)。 所以你应该删除Collection.Register
(v2中的RegisterAll
)注册。 没用。 您已经看到它没用了,因为在您的示例中,您手动启动Command2
,这是正确的做法。
您在最后三行代码中所做的是将未知类型的命令分派给正确的命令处理程序注册。 你总是需要一些反思来解决这个问题,因为你需要根据命令类型构建封闭的ICommandHandler
类型,这是你在编译时不知道的。 您也可以使用.NETreflectionAPI代替使用C# dynamic
关键字,但根据我的经验,在这种特殊情况下使用dynamic
更好。 reflectionAPI的一个重要缺点是API将始终使用InvocationException
包装任何抛出的exception(如果发生故障),并且这使得对调用堆栈执行某些exception处理变得更加困难。
长话短说,这应该是你的注册:
Container container = new Container(); container.Register( typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly); container.RegisterDecorator( typeof(ICommandHandler<>), typeof(CommandDecorator<>));
这应该是调度逻辑:
var type = typeof(ICommandHandler<>).MakeGenericType(command.GetType()); dynamic handler = container.GetInstance(type); handler.Execute((dynamic)command);