C# 针对不同命令使用不同装饰器的简单注入器

C# 针对不同命令使用不同装饰器的简单注入器,c#,.net,inversion-of-control,ioc-container,simple-injector,C#,.net,Inversion Of Control,Ioc Container,Simple Injector,您好,我开始使用我的所有项目,并想就如何适应我的要求是强大的功能一些建议 我有两个命令处理程序装饰器,它们将包装命令: public class TransactionCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> { private readonly ICommandHandler<TCommand> handlerToCall; private readon

您好,我开始使用我的所有项目,并想就如何适应我的要求是强大的功能一些建议

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

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();
    }
}
公共类TransactionCommandHandlerDecorator
:ICommandHandler
{
私有只读ICommandHandler handlerToCall;
私有只读IUnitOfWork;
公共事务CommandHandlerDecorator(
i工作单元工作单元,
ICommandHandler(已装饰)
{
this.handlerToCall=装饰;
this.unitOfWork=unitOfWork;
}
公共无效句柄(TCommand命令)
{
this.handlerToCall.Handle(命令);
unitOfWork.Save();
}
}
互斥装饰器:

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
:ICommandHandler
{
私有只读ICommandHandler handlerToCall;
私有只读IUnitOfWork;
私有静态对象锁=新对象();
带有MutexDecorator的公共事务CommandHandler(
i工作单元工作单元,
ICommandHandler(已装饰)
{
this.handlerToCall=装饰;
this.unitOfWork=unitOfWork;
}
公共无效句柄(TCommand命令)
{
锁(锁)
{
this.handlerToCall.Handle(命令);
unitOfWork.Save();
}
}
}
在某些情况下,只有以这种阻塞方式包装某些命令(通过使用TransactionCommandHandlerWithMutexDecorator)才有意义,并允许其他线程(使用TransactionCommandHandlerDecorator)之间的无连接访问,此外,如果命令类型之间不共享互斥锁(使用我的当前代码),锁是静态的,可以在所有类型之间共享

关于我的问题:

1) 如何将TransactionCommandHandlerWithMutexDecorator应用于一个或多个特定命令,并对其余命令使用TransactionCommandHandlerDecorator?是否使用ExpressionBuild事件

2) 我需要为我想要修饰的每个命令创建一个新类(以确保每个命令都有一个唯一的锁对象),还是有更好的方法(使用拦截)

感谢您提供有关执行上述操作的最佳方法的建议

谢谢

克里斯

在我当前的代码中,锁是静态的,可以在 所有类型

这是不正确的。对于每个
t命令
都将有一个新的静态类型。换句话说,
Decorator
将具有与
Decorator
不同的
静态对象锁
实例

如果您想让它反过来,因此对所有命令都有一个单独的锁,这将有点困难。你基本上可以做三件事:

  • 从非泛型基派生装饰器并在那里定义锁
  • 在静态非泛型类中定义锁,并从泛型装饰器中引用该类
  • 将锁移动到非泛型类,并将其作为普通依赖项注入到装饰器中
  • 但是,这不是你想要的。您想要的行为是默认情况下发生的,这与简单的喷油器无关。这就是泛型在C#和.NET中的工作方式

    如何将TransactionCommandHandlerWithMutexDecorator应用于 一个或多个特定命令,并使用 TransactionCommandHandlerDecorator用于其余部分

    这比你想象的要容易。有一个
    RegisterDecorator
    重载,它接受一个
    谓词
    ,允许您告诉何时进行装饰。这可能是这样的:

    // 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)));
    
    //一些助手方法
    私有静态类型GetCommandType(类型handlerType)
    {
    返回handlerType.GetGenericArguments()[0];
    }
    私有静态bool IsMutexCommand(类型commandType)
    {
    //这里确定一个类是一个互斥命令。
    //例如:
    返回类型为(IMutexCommand)。IsAssignableFrom(commandType);
    }
    //使用谓词进行装饰器注册。
    container.RegisterDecorator(
    类型(ICommandHandler),
    类型(TransactionCommandHandlerWithMutexDecorator),
    c=>IsMutexCommand(GetCommandType(c.ServiceType));
    //使用谓词进行装饰器注册。
    container.RegisterDecorator(
    类型(ICommandHandler),
    类型(TransactionCommandHandlerDecorator),
    c=>!IsMutexCommand(GetCommandType(c.ServiceType));
    
    与简单喷油器一样,
    寄存器检测器
    经过高度优化。在正常情况下*谓词只调用一次


    *当多个线程同时请求同一实例时,谓词可能会被多次调用,但在缓存生成的表达式并生成委托后,谓词将不再被调用。

    谢谢Steven,我刚刚意识到阅读了您的回复,您是对的,使用特定的具体实现,完全可以满足我的需求。感谢您迄今为止的帮助,我将如何按照问题#1仅装饰部分命令?@g18c:抱歉,我错过了您的最后一个问题。请看我的更新。