Dependency injection 为什么不把你的IoC容器传来传去呢?

Dependency injection 为什么不把你的IoC容器传来传去呢?,dependency-injection,inversion-of-control,Dependency Injection,Inversion Of Control,在AutoFac的“最佳实践”页面()上,他们说: 不要把容器到处传递 赋予组件对容器的访问权,或将其存储在公共静态属性中,或使全局“IoC”类上的函数(如Resolve())可用,都无法达到使用依赖项注入的目的。这种设计与服务定位器模式有更多的共同点。 如果组件依赖于容器,请查看它们如何使用容器检索服务,并将这些服务添加到组件的(依赖注入的)构造函数参数中 那么,让一个组件“动态”实例化另一个组件的更好方法是什么呢?他们的第二段没有涵盖需要创建的组件取决于系统状态的情况。或者当组件A需要创建X

在AutoFac的“最佳实践”页面()上,他们说:

不要把容器到处传递 赋予组件对容器的访问权,或将其存储在公共静态属性中,或使全局“IoC”类上的函数(如Resolve())可用,都无法达到使用依赖项注入的目的。这种设计与服务定位器模式有更多的共同点。 如果组件依赖于容器,请查看它们如何使用容器检索服务,并将这些服务添加到组件的(依赖注入的)构造函数参数中


那么,让一个组件“动态”实例化另一个组件的更好方法是什么呢?他们的第二段没有涵盖需要创建的组件取决于系统状态的情况。或者当组件A需要创建X个组件B时。

服务定位器模式更难测试,当然也更难控制依赖关系,这可能会导致系统中的耦合比您真正想要的更多

如果您真的想要像延迟实例化这样的东西,您仍然可以选择服务定位器样式(它不会马上杀死您,如果您坚持使用容器接口,那么使用一些模拟框架进行测试并不太困难)。请记住,尽管在构造函数中不做很多(或任何事情)的类的实例化非常便宜

我知道的容器(到目前为止不是autofac)将允许您根据系统的状态修改应该注入哪个实例的依赖项,这样即使这些决定也可以外部化到容器的配置中


这可以为您提供足够的灵活性,而无需根据您在使用依赖项的实例中访问的某些状态来实现与容器的交互。

IoC负责确定给定对象应使用的依赖项版本。这对于创建实现接口的对象链以及对该接口具有依赖关系(类似于命令链或装饰器模式)等操作非常有用


通过传递您的容器,您将责任放在单个对象上,以获得适当的依赖关系,因此它必须知道如何。对于典型的IoC用法,对象只需声明它具有依赖关系,而不必考虑在该依赖关系的多个可用实现之间进行选择。

要抽象出另一个组件的实例化,可以使用Factory模式:

public interface IComponentBFactory
{
    IComponentB CreateComponentB();
}

public class ComponentA : IComponentA
{
    private IComponentBFactory _componentBFactory;

    public ComponentA(IComponentBFactory componentBFactory)
    {
        _componentBFactory = componentBFactory;
    }

    public void Foo()
    {
        var componentB = _componentBFactory.CreateComponentB();

        ...
    }
}
然后可以在IoC容器中注册实现


容器是组装对象图的一种方式,但它肯定不是唯一的方式。这是一个实现细节。让对象不受这些知识的影响,可以使它们与基础设施无关。它还使他们不必知道要解决的依赖项的哪个版本。

Autofac实际上有一些特殊的功能,正好适用于这种情况-详细信息在此处的wiki上:

本质上,如果A需要创建B的多个实例,A可以依赖Func,而Autofac将生成一个从容器中返回新B的实现

上述其他建议当然有效——Autofac的方法有两个不同之处:

  • 它避免了对大量工厂接口的需要
  • B(工厂的产品)仍然可以由容器注入依赖项
希望这有帮助


尼克

我也打算提出同样的建议。在我看来,这就是我要走的路。回答得好,布莱恩。我其实知道答案。。。但问一个问题似乎是我在StackOverflow系统上获得分数的唯一途径。很好的解释!有人理解最后一段吗?@msfanboy-是的,很难理解。我不得不读了三遍,在脑海中停顿一下,把这段文字分成几个容易理解的部分。但这可能是因为英语不是我的母语:DUnity也支持这样的自动工厂。现在许多容器都支持这样做-Funq和Autofac启动了这一功能,但它已经成为一种相当标准的方法。答案中的链接已被弃用-这似乎是Autofac中对委派工厂的更新引用