什么是IOC容器实际上在这里为我做什么?

时间:2011-08-09 19:06:50

标签: c# .net inversion-of-control unity-container ioc-container

所以我完全重构了构造函数注入,现在我有一个类似于这个的bootstrapper类:

var container = new UnityContainer();
container.RegisterType<Type1, Impl1>();
container.RegisterType<Type2, Impl2>();
container.RegisterType<Type3, Impl3>();
container.RegisterType<Type4, Impl4>();

var type4Impl = container.Resolve((typeof)Type4) as Type4;
type4Impl.Run();

我盯着它看了一会儿才意识到Unity对我来说真的没什么特别的。离开ctor sigs,上面的内容可以写成:

Type1 type1Impl = Impl1();
Type2 type2Impl = Impl2();
Type3 type3Impl = Impl3(type1Impl, type2Impl);
Type4 type4Impl = Impl4(type1Impl, type3Impl);
type4Impl.Run();

构造函数注入重构很棒,真正打开了代码的可测试性。但是,我在这里怀疑Unity的用处。我意识到我可能以有限的方式使用框架(即不在任何地方注入容器,使用代码而不是XML进行配置,而不是利用生命周期管理选项),但我没有看到它在这个示例中实际上是如何帮助的。我已经阅读了不止一条评论,其中的观点是DI最好只用作模式,没有容器。这是一个很好的例子吗?这个解决方案还有哪些其他好处让我错过了?

7 个答案:

答案 0 :(得分:6)

我发现当容器中有许多类型相互依赖时,DI容器会变得有价值。正是在这一点上,容器的自动连接功能才会闪耀。

如果您在找到对象时发现您指的是容器,那么您实际上是在遵循服务定位器模式。

答案 1 :(得分:3)

在某种程度上你是对的。 控制反转根本不需要意味着使用IoC容器。如果您的对象图足够小且方便,可以在某种引导代码中一次创建,那也是控制反转

但是,在更复杂的情况下,使用IoC工具可以简化对象创建。使用IoC工具,您可以管理对象生命周期,从不同的配置组成对象图,或者在编译时不知道整个图,可以轻松推迟创建对象等。

没有通用的解决方案。一切都取决于您的具体需求。对于一个只有很少类的简单项目,使用IoC可能会比使用IoC更烦人。对于一个大项目,我甚至无法想象引导代码如何看起来像。

答案 2 :(得分:1)

不同之处在于您正在执行依赖注入而不是Unity执行依赖注入。在您的示例中,您必须知道需要将代码与这些类型相关联的类型。您现在需要在代码中知道,只要您需要Type1,就应该创建Impl1。

答案 3 :(得分:1)

有关此问题的广泛回复,请参阅my post here

这里的大多数其他答案都是正确的,并说几乎相同的事情。我想补充一点,大多数IoC容器允许您自动将类型绑定到自身,或按惯例使用绑定。如果你设置Unity来做那个,那么你可以完全摆脱所有绑定代码。

答案 4 :(得分:1)

这是一个简单的代码说明其他人所说的内容(虽然采取了一些自由,注入属性而不是构造函数注入,并假设您已经注册了类型等)。

public interface IFoo { }
public interface IBar { IFoo FooImpl { get; set; } }
public interface IBaz { IBar BarImpl { get; set; } }
public interface IBat { IBaz BazImpl { get; set; } }

随着对象图的增长以及依赖关系在图表中进一步嵌套,您将不得不提供整个树:

var bat = new Bat{
        BazImpl = new BazImpl() {
                    BarImpl = new BarImpl() {
                        FooImpl = new FooImpl()
                        }
                    }
                };

但是,如果您正确使用容器,则所有分辨率都取决于您注册的内容:

var bat = container.Resolve<IBat>()

答案 5 :(得分:1)

就像其他答案可能已经说过的那样,不需要IoC容器来执行依赖注入。它只是提供自动依赖注入。如果您没有从自动化中获得太多好处,那么不要过多担心容器,尤其是在您注入初始对象的应用程序的入口点。

然而,IoC可以使一些事情变得更容易:

  • 延迟初始化。 Autofac和其他一些人(不确定Unity)可以检测到Func<IMyDependency>的构造函数,并且在注册IDependency的情况下,会自动生成相应的工厂方法。这减少了DI系统中经常需要的前端负载,其中许多大型对象(如存储库)必须初始化并传递到顶级对象。
  • 子依赖隐藏。假设A类需要实例化B类,而B需要C,但A不应该知道C.也许甚至创建A的Z类甚至都不知道C.这就是IoC创建的东西;将A,B和C扔进容器中,摇匀并分解完全水合的B给A,或者可以注入A(自动)的工厂方法,A可以用来创建所有B参考它想要。
  • 简单的“单身”。不管创建和使用静态单例,都可以告诉IoC创建并返回任何已注册依赖项的一个且仅返回一个实例,无论要求多少次依赖。这允许开发人员将任何普通的实例类转换为单例以便在容器中使用,而不需要对类本身进行代码更改。

答案 6 :(得分:0)

您的示例非常简单,如果不使用DI框架,对象图很容易管理。如果这确实是需要的程度,那么手动DI可以正常工作。

随着依赖图变得更加复杂,使用DI框架的价值会迅速上升。

相关问题