问题描述
在我的数据访问层中,我具有一个类似于以下内容的存储库层次结构:
In my data access layer I have a repository hierarchy that looks like this:
<TEntity>
IEntityRepository<---------+ICustomerRepository
^ ^
| |
| |
| |
+ |
<TEntity> +
EntityRepository<----------+CustomerRepository
The IEntityRepository< TEntity>
接口定义基本的CRUD操作,无论实体类型如何,该操作都将有用。 EntityRepository< TEntity>
是这些操作的具体实现。
The IEntityRepository<TEntity>
interface defines basic CRUD operations that will be useful regardless of entity type. EntityRepository<TEntity>
is a concrete implementation of these operations.
此外,还有一些操作的存储库类型是特定于特定实体的。在上面的示例中,我有一个 Customer
实体,并且 ICustomerRepository
接口定义了诸如 GetByPhoneNumber 。 ICustomerRepository
也是从 IEntityRepository< Customer>
派生的,因此通用CRUD操作也可用于 ICustomerRepository
。最后, CustomerRepository
是 ICustomerRepository
操作的具体实现,它也继承自 EntityRepository< ; Customer>
用于常见的操作实现。
In addition, there are repository types for operations that are specific to a particular entity. In the example above, I have a Customer
entity, and the ICustomerRepository
interface defines operations such as GetByPhoneNumber
. The ICustomerRepository
also derives from IEntityRepository<Customer>
, so that the common CRUD operations will also be available for an instance of ICustomerRepository
. Finally, CustomerRepository
is the concrete implementation for the ICustomerRepository
operations, and it also inherits from EntityRepository<Customer>
for the common operations implementation.
因此,转到我的实际问题:我使用简单注入器将实例注入到应用程序中。我在容器中注册了每种专用存储库类型: CustomerRepository
作为 ICustomerRepository
的实现,等等。
So, going over to my actual question: I use Simple Injector to inject instances into my application. I register each of the specialized repository types in my container: CustomerRepository
as the implementation of ICustomerRepository
and so on.
为了确保可以将新的实体类型添加到系统中并使用它们,而无需创建新的具体存储库实现,我希望能够为基础 IEntityRepository<> 的code> EntityRepository<> 实现。我知道我可以为此使用 RegisterOpenGeneric
方法。
To ensure new entity types can be added to the system and used without needing to create a new, concrete repository implementation as well, I would like to be able to serve the base EntityRepository<>
implementation when an IEntityRepository<>
of the new entity is requested. I've understood I can use the RegisterOpenGeneric
method for this.
我不知道的是,当请求通用存储库时,如何为该类型的专用存储库(如果存在)提供服务,而该通用存储库仅作为后备?
What I can't figure out is, when a generic repository is requested, how can I serve the specialized repository for that type if it exists, and the generic repository only as a fallback?
例如,我在应用程序中执行此操作:
For example, let's say I do this in my application:
container.Register<ICustomerRepository, CustomerRepository>();
container.RegisterOpenGeneric(typeof(IEntityRepository<>), typeof(EntityRepository<>));
大多数依赖存储库的类将请求 ICustomerRepository
直接。但是,我的应用程序中可能会有一个类请求基本接口,如下所示:
Most of the classes relying on repositories would request the ICustomerRepository
directly. However, there could be a class in my application requesting the base interface, like this:
public ContractValidator(IEntityRepository<Customer> customerRepository,
IEntityRepository<Contract> contractRepository)
{
...
在上面的示例中发生的事情是:
What happens in the example above is:
-
customerRepository
获取一个实例EntityRepository< Customer>
-
contractRepository
获取<$ c $的实例c> EntityRepository<合同>
customerRepository
gets an instance ofEntityRepository<Customer>
contractRepository
gets an instance ofEntityRepository<Contract>
我想发生的事情是:
-
customerRepository
获取CustomerRepository
-
contractRepository
获取EntityRepository< Contract>
$ b $的实例b
customerRepository
gets an instance ofCustomerRepository
contractRepository
gets an instance ofEntityRepository<Contract>
有什么方法可以通知Simple Injector的分辨率存在一个特定的接口,应该代替它吗?因此,对于 IDerived:IBase
,对 IBase
的请求应返回 IDerived $的实现。 c $ c>(如果存在)。而且我不希望针对所有存储库都采用这种解决方案。是否可以通过合理的方式完成,还是需要手动遍历
RegisterOpenGeneric
谓词中的所有注册并手动进行检查?
Is there any way to inform Simple Injector's resolution that if a derivation of a particular interface exists, this should be served instead? So for IDerived : IBase
, requests for IBase
should return an implementation of IDerived
if it exists. And I don't want this resolution across the board, just for these repositories. Can it be done in a reasonable way, or would I need to manually iterate through all the registrations in the RegisterOpenGeneric
predicate and check manually?
推荐答案
假设您的班级是这样的
public class CustomerRepository :
ICustomerRepository,
IEntityRepository<Customer> { }
您可以注册 IEntityRepository<>
使用 RegisterManyForOpenGeneric
,后备注册保持不变。
You can register all the generic implementations of IEntityRepository<>
using RegisterManyForOpenGeneric
and the fallback registration stays the same.
更新:已更新使用v3语法
// Simple Injector v3.x
container.Register<ICustomerRepository, CustomerRepository>();
container.Register(
typeof(IEntityRepository<>),
new[] { typeof(IEntityRepository<>).Assembly });
container.RegisterConditional(
typeof(IEntityRepository<>),
typeof(EntityRepository<>),
c => !c.Handled);
// Simple Injector v2.x
container.Register<ICustomerRepository, CustomerRepository>();
container.RegisterManyForOpenGeneric(
typeof(IEntityRepository<>),
new[] { typeof(IEntityRepository<>).Assembly });
container.RegisterOpenGeneric(
typeof(IEntityRepository<>),
typeof(EntityRepository<>));
但是您应该注意,如果您使用任何生活方式,那么这些单独的注册可能无法按预期解决。这就是。
But you should note that if you use any lifestyle then these separate registrations may not resolve as you would expect. This is known as a torn lifestyle.
这篇关于如何使Simple Injector偏爱“最衍生”的实现?接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!