本文介绍了如何使Simple Injector偏爱“最衍生”的实现?接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的数据访问层中,我具有一个类似于以下内容的存储库层次结构:

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 ICustomerRepositorydirectly. 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 of EntityRepository<Customer>
  • contractRepository gets an instance of EntityRepository<Contract>

我想发生的事情是:


  • customerRepository 获取 CustomerRepository
  • contractRepository 获取 EntityRepository< Contract>
  • $ b $的实例b
  • customerRepository gets an instance of CustomerRepository
  • contractRepository gets an instance of EntityRepository<Contract>

有什么方法可以通知Simple Injector的分辨率存在一个特定的接口,应该代替它吗?因此,对于 IDerived:IBase ,对 IBase 的请求应返回 IDerived (如果存在)。而且我不希望针对所有存储库都采用这种解决方案。是否可以通过合理的方式完成,还是需要手动遍历 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偏爱“最衍生”的实现?接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 00:57