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

Ara*_*ind 7 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

装饰:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

示例程序

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*ven 6

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

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

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

Container container = new Container();

container.Register(
    typeof(ICommandHandler<>),
    typeof(ICommandHandler<>).Assembly);

container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(CommandDecorator<>));
Run Code Online (Sandbox Code Playgroud)

这应该是调度逻辑:

var type = typeof(ICommandHandler<>).MakeGenericType(command.GetType());

dynamic handler = container.GetInstance(type);
handler.Execute((dynamic)command);
Run Code Online (Sandbox Code Playgroud)