简单的注入器使用不同的装饰器来执行不同的命令

g18*_*18c 4 .net c# ioc-container inversion-of-control simple-injector

嗨我开始在我的所有项目中使用Simple Injector DI容器,并且想要一些关于如何适应的建议是我的要求的强大功能.

我有几个命令处理程序装饰器,它将包装命令:

public class TransactionCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> handlerToCall;
    private readonly IUnitOfWork unitOfWork;

    public TransactionCommandHandlerDecorator(
        IUnitOfWork unitOfWork, 
        ICommandHandler<TCommand> decorated)
    {
        this.handlerToCall = decorated;
        this.unitOfWork = unitOfWork;
    }

    public void Handle(TCommand command)
    {
         this.handlerToCall.Handle(command);
         unitOfWork.Save();
    }
}
Run Code Online (Sandbox Code Playgroud)

互斥装饰者:

public class TransactionCommandHandlerWithMutexDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> handlerToCall;
    private readonly IUnitOfWork unitOfWork;
    private static object Lock = new object();

    public TransactionCommandHandlerWithMutexDecorator(
        IUnitOfWork unitOfWork, 
        ICommandHandler<TCommand> decorated)
    {
        this.handlerToCall = decorated;
        this.unitOfWork = unitOfWork;
    }

    public void Handle(TCommand command)
    {
        lock (Lock)
        {
            this.handlerToCall.Handle(command);
            unitOfWork.Save();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,只有以这种阻塞方式包装一些命令才有意义(通过使用TransactionCommandHandlerWithMutexDecorator),并允许其他人通过所有线程(使用TransactionCommandHandlerDecorator)进行精确访问,此外如果不在命令类型之间共享互斥锁,那将是很好的 - 我当前的代码,锁是静态的,将在所有类型之间共享.

所以我的问题:

1)如何将TransactionCommandHandlerWithMutexDecorator应用于特定的命令或命令,并使用TransactionCommandHandlerDecorator进行其余的操作 - 我会使用ExpressionBuilt事件吗?

2)我是否需要为每个我想要装饰的命令创建一个新类(以确保每个命令都有一个唯一的锁对象),或者是否有一些更好的方式(使用拦截)?

关于如何做到这一点的最佳方式的建议.

谢谢,

克里斯

Ste*_*ven 8

使用我当前的代码,锁是静态的,并且将在所有类型之间共享.

这是不正确的.通用类型不共享静态成员.每一个TCommand都会有一个新的静态类型.换句话说,一个Decorator<int>将拥有与一个不同的static object Lock实例Decorator<string>.

如果你想要反过来,因此对所有命令都有1个单锁,这将有点困难.你基本上可以做三件事:

  1. 从非泛型基础派生装饰器并在那里定义锁定.
  2. 在静态非泛型类中定义锁,并在泛型装饰器中引用该类.
  3. 将锁移动到非泛型类,并将其作为普通依赖项注入装饰器.

但同样,这不是你想要的.您想要的行为是默认情况下发生的行为,这与Simple Injector无关.这就是泛型在C#和.NET中的工作方式.

如何将TransactionCommandHandlerWithMutexDecorator应用于特定命令或命令,并使用TransactionCommandHandlerDecorator进行其余操作

这比你想象的要容易得多.有一个带有a的RegisterDecorator重载Predicate<T>,它允许你告诉何时装饰.这可能如下所示:

// Some helper methods
private static Type GetCommandType(Type handlerType)
{
    return handlerType.GetGenericArguments()[0];
}

private static bool IsMutexCommand(Type commandType)
{
    // Determine here is a class is a mutex command. 
    // Example:
    return typeof(IMutexCommand).IsAssignableFrom(commandType);
}

// Decorator registration with predicates.
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerWithMutexDecorator<>),
    c => IsMutexCommand(GetCommandType(c.ServiceType)));

// Decorator registration with predicates.
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>),
    c => !IsMutexCommand(GetCommandType(c.ServiceType)));
Run Code Online (Sandbox Code Playgroud)

由于Simple Injector的所有功能都经过了RegisterDecorator高度优化.在正常情况下*谓词只会被调用一次.

*当多个线程同时同时请求相同的实例时,谓词被多次调用是可能的,但是在构建的表达式被缓存并且构建了委托之后,谓词将不再被调用.