在使用DI框架时,我觉得有可能用脚射击自己 (我选择的框架是ninject,所以我将在我的例子中使用它。)
我要退后一步,看看DI 框架存在的原因:
为了防止必须手工进行DI
这是正确的,根据Ninjects文档的精神,我们假设我们有一个创建Dojo
的{{1}}。这些Samurai
在制作时会被Samurai
。
IWeapon
现在我的理解是,class Samurai{
readonly IWeapon weapon;
public Samurai(IWeapon weapon){
this.weapon = weapon;
}
}
在创建Dojo
时会使用Kernel.Get<IWeapon>()
。
哇
我不是只把我的Dojo连接到内核吗?
另外......如何获得内核:DI,单身,服务地点?
我觉得我们很快就打败了DI的目的,因为现在我依赖于我的DI框架。如果忍者被击败并且ninject也会死亡会怎么样?
如何在不与DI框架耦合的情况下使用DI?
我确定之前已经问过这个问题但是找不到任何东西。请使用评论发布相关问题,以便我们汇集知识以找出最佳解决方案。
答案 0 :(得分:5)
在执行依赖注入时,技巧是让所有类通过构造函数注入其依赖项。通过这种方式,您可以让内核从根对象中为您构建完整的对象图。
然而,这个“根对象”必须通过调用kernel.Get<HomeController>()
直接解决(如果HomeController
是根对象)。因此,在您的应用程序中,您必须致电kernel.Get
。没有它是不可能的。
诀窍是将此最小化到理想情况下应用程序中的单行代码并将其置于启动路径附近。可能靠近您注册依赖项的地方。该应用程序的其余部分无法使用任何DI框架。
甚至还有Ninject和其他容器的集成包,允许您根据您使用的应用程序平台删除该单行代码。例如,ASP.NET MVC具有很好的可扩展性点,允许您插入ControllerFactory
,允许您让工厂为您调用kernel.Get
。
如何在不与DI框架耦合的情况下使用DI?
总会有一些耦合,但理想情况下这应该只是启动路径。所有其他代码都应该忽略容器的使用。仍然存在程序集依赖关系,但此依赖关系仅存在于启动项目中,而不存在于业务层中。
看看DI框架存在的原因:为了防止必须做DI 手
更准确。 DI有助于使您的应用程序更易于维护。 DI框架有助于使应用程序的启动路径(a.k.a。composition root)更易于维护。
答案 1 :(得分:2)
实际上服务定位器设计模式被认为是有害的(实际上从许多角度来看considered as anti-pattern),所以我强烈反对在代码中使用它。
使用服务定位器会导致您的班级(class Dojo
)与其客户之间的界面不清晰。阅读你的类标题是不可能理解所需的上下文:我应该怎样做才能正确使用这个类:我应该把什么放在满足所有要求的内容中。
实际上,当我们在应用程序的一个地方使用容器(也就是服务定位器)时,我更喜欢使用另一个名为Composition Root的模式:在应用程序的根目录中,如Main
, HomeController
等。
我强烈建议您查看有关该主题的书籍:Mark Seeman的"Dependency Injection in .NET",其中详细介绍了所有这些主题。
答案 2 :(得分:1)
您还可以对DI容器进行某种抽象。考虑这样的界面,
public interface IDependencyResolver
{
T Get<T>();
}
然后你有一个实现 - 对于Ninject它可能看起来像这样。
public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IKernel _kernel = new StandardKernel();
public T Get<T>()
{
return _kernel.Get<T>();
}
}
这意味着您可以像项目中的任何其他第三方组件一样使用Ninject,但读取的行除外
IDependencyResolver resolver = new NinjectDependencyResolver();
根据您的需要,只能在某处找到。然后使用您的IDependencyResolver
实例而不是Ninject提供的IKernel
(或其他框架的类似容器)。
要切换DI容器,只需要实现新的IDependencyResolver
。