您好我开始在我的所有项目中使用Simple Injector DI container,并希望就如何适应提供一些强有力的功能来满足我的要求。
我有几个命令处理程序装饰器将包装命令:
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();
}
}
Mutex装饰器:
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();
}
}
}
在某些情况下,只有以这种阻塞方式包装一些命令才有意义(通过使用TransactionCommandHandlerWithMutexDecorator),并允许其他人通过所有线程(使用TransactionCommandHandlerDecorator)进行精确访问,此外如果在命令之间不共享互斥锁会很好types - 使用我当前的代码,锁是静态的,并且将在所有类型之间共享。
所以我的问题:
1)如何将TransactionCommandHandlerWithMutexDecorator应用于特定的一个或多个命令,并使用TransactionCommandHandlerDecorator进行其余的操作 - 我会使用ExpressionBuilt事件吗?
2)我是否需要为每个我想装饰的命令创建一个新类(以确保每个命令都有一个唯一的锁对象),或者是否有一些更好的方式(使用拦截)?
赞赏有关上述方法的最佳方法的建议。
谢谢,
克里斯
答案 0 :(得分:8)
使用我当前的代码,锁是静态的,并且将在它们之间共享 所有类型。
这是不正确的。 Generic types don't share static members。对于每个TCommand
,都会有一个新的静态类型。换句话说,Decorator<int>
将具有与static object Lock
不同的Decorator<string>
个实例。
如果您想要反过来,因此对所有命令都有1个单锁,这将会有点困难。你基本上可以做三件事:
但同样,这不是你想要的。您想要的行为是默认情况下发生的行为,这与Simple Injector无关。这就是泛型在C#和.NET中的工作方式。
如何将TransactionCommandHandlerWithMutexDecorator应用于 特定命令或命令,以及使用 其余的TransactionCommandHandlerDecorator
这比你想象的要容易得多。 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)));
作为Simple Injector的一切,RegisterDecorator
得到了高度优化。在正常情况下*谓词只会被调用一次。
*可能多次调用谓词,当多个线程同时同时请求同一个实例时,但在缓存构建的表达式并构建委托之后,谓词将不再被调用。