我想用简单注入器修饰以下继承(将其重命名以使其更具可读性):
interface IGetData<T,U> { }
interface ICustomerService : IGetData<Customer, Guid> { }
class CustomerServiceImpl : ICustomerService { }
我有一个名为IGetData<T,U>
的{{1}}装饰器,还有一个名为GetDataDecorator
的{{1}}装饰器。我的目标是为ICustomerService
有两个(链接的)装饰器,一个基于CustomerServicePermissionDecorator
接口,一个基于CustomerServiceImpl
接口。我在启动时注册了两个装饰器:
IGetData<T,U>
第一次注册工作正常,ICustomerService
中的断点表明从container.RegisterDecorator<ICustomerService, CustomerServicePermissionDecorator>();
container.RegisterDecorator(typeof(IGetData<,>), typeof(GetDataDecorator<,>));
调用了那里的方法。但是,CustomerServiceImpl
方法从不执行。
我想这是我的误解-我在做什么错了?
答案 0 :(得分:3)
在这些复杂的情况下,通常有助于手动编写对象图,因为这样可以使发生的事情更加直观。它甚至允许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
从第三行可以看出,从技术上讲,可以使用ICustomerService
装饰器装饰GetDataDecorator<Customer, Guid>
。但是,由于GetDataDecorator<T, U>
没有实现ICustomerService
,因此不可能将该装饰器注入任何需要ICustomerService
的使用者中。这就是示例中最后一行代码给出编译错误的原因。
由于无法使用普通的旧C#构造此对象图,因此Simple Injector也将无法执行此操作。它受限于公共语言运行时给出的限制。
但是,在这种情况下,简单注入器比CLR更具限制性,因为前面示例中的任何ICustomerService
都可以用GetDataDecorator<Customer, Guid>
装饰。可以构造依赖GetData<Customer, Guid>
的使用者。但是Simple Injector不允许这样做。
不允许这样做的原因之一是为了防止非常复杂和混乱的情况,在某些情况下使用装饰器,而在另一些情况下省略装饰器。这就是为什么Simple Injector会强制您明确声明应在其上应用装饰器的接口。 Simple Injector将不沿继承链寻找基本接口,这似乎是您所期望的行为。
尽管很难对您的设计发表评论,但是您可能要考虑一起删除ICustomerService
。特别是因为您已经在使用通用接口。我经常看到开发人员试图通过在通用和非通用之间混合使用旧的SOLID接口(最可能是ICustomerService
),但是效果总是不好。您应该全力以赴,放弃过于宽泛的非通用接口。当您这样做时,Simple Injector会为您简化装饰器的应用。