我目前正在开展一个项目,而且主要是基于图书馆的。
我希望使用依赖注入来使用库,但是我希望库在很大程度上与所使用的容器无关。
我曾经写过一个“桥”库让这种事情变得更容易,但我不确定这是否真的是正确的方法? (图书馆:https://github.com/clintkpearson/IoCBridge)
我不想直接从我的库中引用DI技术(Ninject,Windsor等),因为它使得使用它的人不灵活。
在类似的情况下还有一些其他问题,但似乎没有一个问题能够令人满意地解决问题。
作为旁注:我意识到我可以确保该库遵循一般习惯用法并使用接口和放大器。 ctor依赖关系的参数,然后将它留给消费应用程序来注册容器中的类型。
我能看到的唯一问题(如果我错了,请纠正我)是这需要消费应用程序实际知道哪些类型链接到哪些接口,无论是否需要注册为单身人士等...并且从即插即用的角度来看,这很糟糕。
答案 0 :(得分:2)
有点controversial,但我建议使用穷人注射液。我并不是说它很棒,但它有一些有效的用例(就像服务定位器一样)。它需要更多的维护,但它将使您免于依赖另一个IoC容器注册的库。您应该阅读有关该主题的Mark Seemann's article。
我最近在我的simple library非常InternalsVisibleTo实施了这种方法。基本上你为库的公共类编写了两个构造函数。
internal SitemapProvider(IActionResultFactory actionResultFactory, IBaseUrlProvider baseUrlProvider)
{
_actionResultFactory = actionResultFactory;
_baseUrlProvider = baseUrlProvider;
}
public SitemapProvider() : this(new ActionResultFactory(), new BaseUrlProvider()) { }
正如您所看到的,只有第二个构造函数是公共的,您自己填充依赖项。这也提供了装配级别的封装。您仍然可以通过向程序集添加{{3}}属性来测试此类,并在库中自由使用依赖项注入。用户还可以使用new关键字创建实例,或者将此类的接口添加到其IoC注册中。
我不知道.NET中是否有广泛采用的IoC容器注册库。我想过自己写一个,但每个容器都有自己独特的功能,而且对象生命周期变得更加复杂。此外,人们会因为依赖另一个图书馆而感到不安。
答案 1 :(得分:2)
良好的 DI实现应该在任何对象上启用DI, 后者 DI-agnostic 。
Prism 是一个糟糕的例子,因为最后一次我使用它(2年前)它需要对象是DI不可知的通过强制使用[Injection]
属性。一个很好的非DI不可知的例子是Spring Framework(极受欢迎的Java DI框架,有一个名为Spring.NET的.NET端口),允许通过所谓的上下文文件启用DI - 这些是描述依赖关系的xml文件。后者不必是您库的一部分,将其保留为完全独立的dll文件。
Spring的例子可以告诉你除了编程到接口<之外,你不应该有任何特定的配置,先决条件或模式来使对象可注入,或者允许对象注入它。 / strong>范例,允许以编程方式访问到合适的构造函数和属性setter 。
这并不意味着任何DI框架应该支持操作普通CLR(.NET)对象,即.k.a。POCO-s。某些框架仅依赖于其特定机制,可能不适合与独立于DI的代码一起使用。通常,他们需要直接依赖DI框架到库,我认为你想(并且可能应该)避免。
答案 2 :(得分:0)
我认为您对依赖注入的范围略有误解。 DI是一种模式,是IoC的一个子集,IoC容器使DI简单方便 - 它们协助依赖解析。 IoC可以归类为几种方法的超集,of which DI is one part。
您不需要IoC框架来使依赖注入工作。
如果你真的坚持使用IoC容器而不是利用常规DI(即构造函数参数或强制属性设置)那么你应该提名容器/框架,不要试图通过尝试kludge来成为所有人的所有东西适配器或桥接器。过度工程时要小心。一个库的定义意味着它具有有限且定义明确的功能集,因此它不需要注入大量的依赖项。
他们很可能想要实现某些接口的自己版本
您不需要IoC框架来实现此目的。如果你的构造函数将它们的参数定义为接口,那么实际上你已经实现了DI - 在构造时注入了依赖项,而你对它的实际具体实现一无所知。让调用代码担心它希望传递的接口实现的细节具体细节。