gpt4 book ai didi

c# - 装饰器装饰基本命令

转载 作者:太空宇宙 更新时间:2023-11-03 18:08:39 25 4
gpt4 key购买 nike

我正在使用 SimpleInjector 2.2.3.0。

我有一个 MVC 4.0 项目,并在我的命令周围使用装饰器模式来管理我的 UnitOfWork 和我的授权。
我有授权的装饰器 - IAuthorisationDecorator .这包含了我所有的 ITransactionalCommandHandlers .
(每个 ITransactionalCommandHandler 也由 IUnitOfWorkDecorator 装饰。)授权装饰器如下所示:

public void Handle(TCommand command)
{
//authorise this command for this Iprincipal

decoratedCommandHandler.Handle(command);
}

我现在想创建一个 INonTransactionalCommandHandler (它不需要 NHibernate session ,它只是做一些文件 IO)。
注意 INonTransactionalCommandHandlerITransactionalCommandHandler继承自 ICommandHandler – 看起来像这样:
 public interface ICommandHandler<in TCommand, out TResult>
{
TResult Result { get; }
void Handle(TCommand command);
}

我真的不想创建两个相同的 AuthorisationDecorators (交易/非交易)。因为最终他们装饰了一个基地 ICommandHandler (实现为 ITransactionalINonTransactional )。

所以我的问题是 - 有什么方法可以创建 1 个装饰底座的装饰器 ICommandHandler - 但是容器知道要抛出 ICommandHandlerITransactionalCommandHandlerINonTransactionalCommandHandler .有没有办法做到这一点?

最佳答案

如果您通过 ICommandHandler<TCommand, TResult> 注册所有命令处理程序接口(interface),您不能使用包装 ITransactionalCommandHandler<TCommand, TResult> 的装饰器来包装部分处理程序.如果处理程序由该 ITransactionalCommandHandler<TCommand, TResult> 显式注册,则只能应用此类装饰器。界面,但这不是你应该做的事情。您不希望这样,因为这意味着这些命令的使用者需要知道处理程序是否是事务性的,他们不应该关心(这是一个实现细节)。

因此,您的事务装饰器应该包装一个 ICommandHandler<TCommand, TResult> .如果它需要访问 ITransactionalCommandHandler<TCommand, TResult>接口(interface),装饰器应该从 ICommandHandler 转换输入参数至ITransactionalCommandHandler .

您需要根据谓词注册装饰器,如下所示:

// NOTE: In Simple Injector v2.x use 'ManyForOpenGeneric' instead.
container.Register(typeof(ICommandHandler<,>), myAssemblies);

container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(TransactionDecorator<,>),
c => typeof(ITransactionalCommandHandler<,>)
.MakeGenericType(c.ServiceType.GetGenericArguments())
.IsAssignableFrom(c.ImplementationType));

container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(AuthorisationDecorator<,>));

谓词确保只有实现 ITransactionalCommandHandler<,> 的命令处理程序被修饰。 .

除了使用该接口(interface),您还可以使用属性标记处理程序:
[Transactional]
class ShipOrderCommandHandler : ICommandHandler<ShipOrderCommand, Unit> { ... }

在这种情况下,注册将变为:
container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(TransactionDecorator<,>), 
c => c.ImplementationType.GetCustomAttribute<TransactionalAttribute>() != null);

另一种选择是使用接口(interface)标记命令本身或从基类继承:
public class ShipOrderCommand : ICommand<Unit>, ITransactionalCommand
{
public Guid OrderId;
}

这允许您在 TransactionDecorator<,> 上添加泛型类型约束。并允许您删除 RegisterDecorator 上的谓词登记:
public class TransactionDecorator<int TCommand, out TResult>
: ICommandHandler<TCommand, TResult>
where TCommand : ITransactionalCommand
{
// etc
}

由于 Simple Injector 理解类型约束,因此您可以将注册简化如下:
container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(TransactionDecorator<,>));

请注意,在这种特殊情况下,我不建议使用最后一种方法,因为实现了 ITransactionalCommand命令上的接口(interface)再次意味着实现细节正在泄漏到命令的定义中。命令及其使用者不需要知道命令处理程序是否需要事务(这在 future 可能会改变)。

关于c# - 装饰器装饰基本命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21231221/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com