Simple Injector:多接口装饰器

Simple Injector: Decorator for multiple interfaces

我有以下继承,我想用 Simple Injector 装饰(重命名内容以使其更具可读性):

interface IGetData<T,U> { }
interface ICustomerService : IGetData<Customer, Guid> { }
class CustomerServiceImpl : ICustomerService { }

我有一个 IGetData<T,U> 的装饰器 GetDataDecorator,我还有另一个 ICustomerService 的装饰器 CustomerServicePermissionDecorator。我的目标是为 CustomerServiceImpl 设置两个(链接的)装饰器,一个基于 IGetData<T,U> 接口,一个基于 ICustomerService 接口。我在启动时注册了两个装饰器:

container.RegisterDecorator<ICustomerService, CustomerServicePermissionDecorator>();
container.RegisterDecorator(typeof(IGetData<,>), typeof(GetDataDecorator<,>));

第一次注册工作正常,CustomerServiceImpl 中的断点显示那里的方法是从 CustomerServicePermissionDecorator 调用的。但是,GetDataDecorator 方法永远不会执行。

我想这是我的误解 - 我做错了什么?

在这些复杂的情况下,手写对象图通常会有所帮助,因为这使得正在发生的事情更加直观。它甚至允许 C# 编译器发出不可桥接问题的信号。

根据您指定的设计,您可以手工构建如下对象图。

ICustomerService impl = new CustomerServiceImpl();

ICustomerService dec1 = new CustomerServicePermissionDecorator(impl);

IGetData<Customer, Guid> dec2 = new GetDataDecorator<Customer, Guid>(dec1);

// Consumer depends on ICustomerService 
var consumer = new Consumer(dec2); <-- compile error

正如您在第三行中看到的,从技术上讲,可以使用 GetDataDecorator<Customer, Guid> 装饰器来装饰 ICustomerService。但是,因为 GetDataDecorator<T, U> 没有实现 ICustomerService,所以不可能将该装饰器注入到任何需要 ICustomerService 的消费者中。这就是例子中最后一行代码给出编译错误的原因。

并且由于此对象图无法使用普通的旧 C# 构造,简单注入器也将无法执行此操作。它受到公共语言运行时给定的限制。

然而,在这种情况下,简单注入器比 CLR 更具限制性,因为前面示例中的任何 ICustomerService 都可以用 GetDataDecorator<Customer, Guid> 修饰。可以构造一个依赖于 GetData<Customer, Guid> 的消费者。但是 Simple Injector 不允许这样做。

禁止这样做的原因之一是为了防止非常复杂和混乱的情况,在这种情况下,装饰器在某些情况下被应用,而在其他情况下被省略。这就是为什么 Simple Injector 会强制您显式声明应在其上应用装饰器的接口。 简单注入器将不会遍历继承链来寻找基接口,这似乎是您所期望的行为。

虽然很难对您的设计发表评论,但您可能要考虑一起删除 ICustomerService。特别是因为您已经在使用通用接口。我经常看到开发人员试图通过在通用和非通用之间进行混合来保留他们的旧接口(ICustomerService 很可能是这样),但这几乎没有效果。您应该全力以赴并放弃过于宽泛的非通用接口。当您这样做时,Simple Injector 将为您简化应用装饰器。