通用命令处理程序的简单注入器用法

时间:2014-05-10 14:27:15

标签: c# dependency-injection dependency-properties simple-injector

根据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<TCommand>
{
    void Execute(TCommand Command);
}

public class Command1Handler : ICommandHandler<Command1>
{
    public void Execute(Command1 Command) {
        Console.WriteLine(Command.Name);
    }
}

public class Command2Handler : ICommandHandler<Command2>
{
    public void Execute(Command2 Command) {
        Console.WriteLine(Command.Name + "Hello");
    }
}

装饰:

public class CommandDecorator<TCommand> : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> _handler;

    public CommandDecorator(ICommandHandler<TCommand> 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<ICommand>(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);
    }
}

这是获得在运行时处理命令的正确处理程序的正确方法。 这是一个示例,在实际应用程序中,命令将发布到队列,服务将读取命令并处理它。 我想装饰器必须用于此但却无法使其工作。 如果有的话,请提出更好的选择。

1 个答案:

答案 0 :(得分:6)

您的命令(Command1Command2)不是服务:它们不应该注册。它们是您通过服务(命令处理程序)传递的运行时数据(消息)。因此,您应该删除Collection.Register<ICommand>(v2中的RegisterAll)注册。没用。您已经看到它没用了,因为在您的示例中,您正在手动修改Command2,这是正确的做法。

您在最后三行代码中所做的是将未知类型的命令分派给正确的命令处理程序注册。你总是需要一些反思来解决这个问题,因为你需要根据命令类型构建关闭的ICommandHandler<TCommand>类型,这是你在编译时不知道的。您也可以使用.NET反射API代替使用C#dynamic关键字,但根据我的经验,在这种特定情况下使用dynamic会更好。反射API的一个重要缺点是API将始终用InvocationException包装任何抛出的异常(如果发生故障),这使得调用堆栈的某些异常处理变得更加困难。

长话短说,这应该是你的注册:

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);