2

我正在尝试在我的新项目中从 Unity 迁移到 Simple Injector。它比 Unity 快得多,我不得不试一试。我有一些颠簸,但没有什么是我无法解决的。但是我用“按键查找”击中了另一个

我读过这篇文章,简单注入器的创建者表示他相信每个接口不需要解析多个类。

我一定是个差劲的程序员,因为我已经用 Unity(它很好地支持它)做到了这一点,并且想在我当前的项目中做到这一点。

我的场景是我有一个 IRepository 接口。我有两个单独的存储库,我想使用 IRepository 接口进行抽象。像这样:

container.Register<FirstData>(() => new FirstData());
container.Register<IRepository>(
           () => new GenericRepository(container.GetInstance<FirstData>()));


container.Register<SecondEntities>(() => new SecondEntities());
container.Register<IRepository>(
           () => new GenericRepository(container.GetInstance<SecondData>()));

IRepository/GenericRepository 是一种相当常见的抽象,但在 SimpleInjector 中只能有一个

在 Unity 中,我可以注册我的两个存储库,然后设置我的构造函数注入来注入我需要的实例。这是使用实例的密钥完成的。(我不需要Resolve在我的正常代码中进行调用,也不需要在我的设置之外添加对 Unity 的依赖项。)

使用简单的注射器这是行不通的。但是,无论好坏,Simple Injector 的所有者都认为这个功能是个坏主意。

注意:作者的“应用内”系统看起来像是使用字符串键进行查找,但每次仍然需要不同的类(DefaultRequestHandlerOrdersRequestHandlerCustomersRequestHandler我只有一个GenericRepostory允许我抽象我的存储库方法,而不管我连接到什么。

GenericRepostory我想每次我想实例化它时我都可以继承我的。或者让它采用我不需要的随机类型参数。但这混淆了我的设计,所以我希望有另一种方法来做到这一点。

那么是否有任何解决方法不让我创建虚假类型来区分我的两个 IRepository/GenericRepository 实例?

4

2 回答 2

2

您自己的答案实际上非常好,但不幸的是您将泛型类型参数视为虚拟参数;你应该让它成为你设计的一等公民:

public interface IRepository<TData> { }

public clss GenericRepository<TData> : IRepository<TData>
{ 
    public GenericRepository(TData data) { }
}

这样您就可以简单地注册它们,如下所示:

container.Register<IRepository<FirstData>, GenericRepository<FirstData>>();
container.Register<IRepository<SecondData>, GenericRepository<SecondData>>();

在这种情况下,您的业务类可以简单地依赖于泛型IRepository<FirstData>IRepository<SecondData>并且可以简单地注册如下:

container.Register<IFirstBusiness, FirstBusiness>();
container.Register<ISecondBusiness, SecondBusiness>();

请注意此处给出的注册如何不使用任何 lambda。Simple Injector 可以为您找到这一点。这使您的 DI 配置更简单、更具可读性,尤其是:更易于维护。

通过这种方式,您可以使您的设计非常明确和明确。IRepository您的设计是模棱两可的,因为您有一个应该映射到多个实现的单一(非通用)接口。尽管这不一定在所有情况下都是坏事,但在大多数情况下,可以而且应该防止这种歧义,因为这会使您的代码和配置复杂化。

此外,由于您的泛型GenericRepository<T>现在映射到泛型,我们可以用一行IRepository<T>替换所有注册:Register<IRepository<T>, GenericRepository<T>>()

// using SimpleInjector.Extensions;
container.RegisterOpenGeneric(typeof(IRepository<>),
    typeof(GenericRepository<>);

更进一步,您的业务类也可以从通用类型中受益。例如看一下这篇文章,其中每个业务操作都有自己的类,但所有业务操作都隐藏在相同的通用ICommandHandler<TCommand>抽象后面。执行此操作时,可以通过一次调用注册所有业务类:

container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>),
    typeof(ICommandHandler<>).Assembly);

此调用在提供的程序集中搜索ICommandHandler<TCommand>接口的实现,并在容器中注册每个找到的实现。您可以添加新的业务逻辑(用例),而无需更改配置。但这只是对业务逻辑进行这种抽象的众多优势之一。另一个很大的优势是它使添加横切关注点(例如日志记录、事务处理、安全性、审计跟踪、缓存等)更容易实现。

于 2013-06-04T22:01:24.560 回答
2

我们最终将我们的通用存储库更改为如下所示:

/// The Type parameter has no funcionality within the repository, 
/// it is only there to help us differentiate when registering 
/// and resolving different repositories with Simple Injector.
public class GenericRepository<TDummyTypeForSimpleInjector> : IRepository

(我们为其添加了一个类型参数)。
然后我们创建了两个这样的虚拟类(我更改了类的名称以匹配我的示例):

// These are just dummy classes that are used to help 
// register and resolve GenericRepositories with Simple Injector.
public class FirstDataSelector { }
public class SecondDataSelector { }

然后我可以像这样注册它们:

container.Register<FirstData>(() => new FirstData());
container.Register(() => new GenericRepository<FirstDataSelector>
                   (container.GetInstance<FirstData>()));


container.Register<SecondEntities>(() => new SecondEntities());
container.Register(() => new GenericRepository<SecondDataSelector>
                   (container.GetInstance<SecondData>()));

(请注意 GenericRepository 上的泛型类型参数,并且我没有将其注册为 IRepository。这两个更改对于完成这项工作至关重要。)

这工作正常。然后我可以在我的业务逻辑的构造函数注入中使用该注册。

container.Register<IFirstBusiness>(() => new FirstBusiness
               (container.GetInstance<GenericRepository<FirstDataSelector>>()));
container.Register<ISecondBusiness>(() => new SecondBusiness
               (container.GetInstance<GenericRepository<SecondDataSelector>>()));

由于我的业务类采用IRepository它工作正常并且不会将 IOC 容器或我的存储库的实现暴露给业务类。

我基本上使用 Type 参数作为 Key 进行查找。(我知道一个黑客,但我的选择有限。)

不得不在我的设计中添加虚拟类有点令人失望,但我们的团队认为这个缺点是值得的,而不是放弃 Simple Injector 并回到 Unity。

于 2013-06-04T20:47:01.740 回答