如何使用 SimpleInjector 将条件装饰器应用于命令处理程序?

How Can I Apply Conditional Decorator to a Command Handler with SimpleInjector?

我有以下命令处理程序接口:

public interface ICommandHandler<TCommand> where TCommand : ICommand
{
    void Handle(TCommand command);
}

我正在使用以下具体内容装饰此接口的实例 class:

public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
    where TCommand : ICommand
{
     public ValidationCommandHandlerDecorator(
         IValidator<TCommand> validator, 
         ICommandHandler<TCommand> handler)
     {
     }

     public void Handle(TCommand command) {  }        
}

但是....我不一定要装饰所有命令处理程序,只想装饰 ICommandHandler<TCommand> IF 实例 exists/is 注册 IValidator<TCommand> 的具体TCommand 的类型。注意 IValidator<TCommand> 实例是在装饰器 class.

的构造函数中注入的

例如,如果我有一个命令处理程序:

public class CreateFooCommandHandler : ICommandHandler<CreateFooCommand>

如果我注册了以下实例,我只想装饰:

public class CreateFooCommandValidator : IValidator<CreateFooCommand>

如果 CreateFooCommandValidator 不存在,那么我不想用 ValidationCommandHandlerDecorator.

装饰 CreateFooCommandHandler

我在注册 SimpleInjector 时使用了以下内容:

var container = new Container();

container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IValidator<>), assemblies);
container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(ValidationCommandHandlerDecorator<>));

显然,如果对于任何给定的 ICommandHandler<> 不存在 IValidator<> 的实例,则此操作显然会失败。 For info assemblies 是用于注册通用 classes.

的程序集集合

如果可能的话,我应该使用什么来注册 decorator/validators 来实现我想做的事情?我不想从使用 SimpleInjector 切换。

此外,如果可能的话,这是推荐还是违反 SOLID 原则,甚至只是代码味道?

您可以通过分析容器中的注册并决定是否装饰每个实例来注册条件装饰器,但我认为这不是最佳选择。最简单的解决方案是为那些实际 IValidator 不存在的实例定义并注册回退 NullValidator ...

public class NullValidator<TCommand> : IValidator<TCommand> where TCommand : ICommand
{
    public void Validate(TCommand command)
    {
    }
}

注册为条件:

var container = new Container();

container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IValidator<>), assemblies);
container.RegisterConditional(
    typeof(IValidator<>), 
    typeof(NullValidator<>), 
    c => !c.Handled);
container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(ValidationCommandHandlerDecorator<>));

container.Verify();

I don't want to switch from using SimpleInjector.

好人!

Furthermore, if it is possible, is this recommended or is it a violation of SOLID principles, or even just a code smell?

这正是 RegisterConditional 存在的原因:-)