如何使简单的注射器更喜欢“最终派生”接口的实现?(How do I make Simple Inje

2019-10-23 15:02发布

在我的数据访问层我有一个仓库层次结构如下所示:

    <TEntity>                                 
IEntityRepository<---------+ICustomerRepository
        ^                            ^        
        |                            |        
        |                            |        
        |                            |        
        +                            |        
    <TEntity>                        +        
 EntityRepository<----------+CustomerRepository

所述IEntityRepository<TEntity>接口定义基本的CRUD操作,这将是有用的,无论实体类型。 EntityRepository<TEntity>是一个具体实现这些操作。

此外,还有仓库类型是针对特定的实体操作。 在上面的例子中,我有一个Customer实体,并且ICustomerRepository接口操作定义如GetByPhoneNumber 。 所述ICustomerRepository也从派生IEntityRepository<Customer> ,从而使公用给CRUD操作也将可用于实例ICustomerRepository 。 最后, CustomerRepository对于具体实施ICustomerRepository操作,它也继承自EntityRepository<Customer>为共同操作实施。

所以,要到我实际的问题:我用简单的注射器注入实例到我的应用程序。 我注册的每个专业库类型在我的容器: CustomerRepository作为实施ICustomerRepository等。

为了确保新的实体类型可以被添加到系统中,并无需创建一个新的,具体的仓库实现以及使用,我想是能够服务于基础EntityRepository<>实施当IEntityRepository<>新实体的是请求。 我明白我可以使用RegisterOpenGeneric方法这一点。

我想不通,当被请求的通用信息库,我怎么能服务于这种类型的专门信息库,如果它存在,一般只有库作为备用?

例如,假设我在我的应用程序做到这一点:

container.Register<ICustomerRepository, CustomerRepository>();
container.RegisterOpenGeneric(typeof(IEntityRepository<>), typeof(EntityRepository<>));

大多数依靠仓库的类将要求ICustomerRepository直接。 但是,有可能是在我的应用程序请求的基本接口,像这样一类:

public ContractValidator(IEntityRepository<Customer> customerRepository,
                         IEntityRepository<Contract> contractRepository)
{
    ...

在本例中,会发生什么上面是:

  • customerRepository得到的一个实例EntityRepository<Customer>
  • contractRepository得到的一个实例EntityRepository<Contract>

我希望发生的是:

  • customerRepository得到的实例CustomerRepository
  • contractRepository得到的一个实例EntityRepository<Contract>

有什么办法告知简单的喷油器的分辨率,如果一个特定接口的推导存在,这应改为投放? 因此,对于IDerived : IBase ,用于请求IBase应该返回的实现IDerived ,如果它的存在。 而且我不希望一刀切这项决议,只是这些库。 它可以以合理的方式来完成,或者我需要在通过所有的注册手动循环RegisterOpenGeneric谓词和手动检查?

Answer 1:

假设你的类这个样子

public class CustomerRepository : 
    ICustomerRepository, 
    IEntityRepository<Customer> { }

可以注册的所有的一般实现方式IEntityRepository<>使用RegisterManyForOpenGeneric和回退登记保持不变。

更新:更新与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<>));

但是你要注意,如果你使用任何的生活方式,那么这些不同的注册可能不会解决你所期望的。 这被称为一个撕裂的生活方式 。



Answer 2:

您不能使用RegisterOpenGenericRegisterManyForOpenGeneric这一点。 你将不得不手工编写一些代码来反映过来类型系统,并找到实现通过其特定的接口进行注册。

在我看来不过你不应该有自定义的存储库。 这些一到OBE映射是因为你这些悲伤再说,你这样做违反了SOLID原则。 如果可以的话,如上所述考虑设计在这里 。



文章来源: How do I make Simple Injector prefer implementations of the “most derived” interface?