代码之家  ›  专栏  ›  技术社区  ›  Ryu

IOC容器的最佳实践

  •  26
  • Ryu  · 技术社区  · 16 年前

    是否每个类都应该有一个IUnityContainer成员,然后由构造函数传入容器?是否应该有一个带有IOC容器的单例类?

    asp.net开发怎么样?

    有人能给我指路吗?谢谢

    6 回复  |  直到 16 年前
        1
  •  22
  •   Thorsten Lorenz    15 年前

    IMHO不建议将整个容器注入到类中,也不建议使用应用程序范围的静态IoC服务定位器。

    您希望能够从类的构造函数(我们称之为Foo)中看到它正在使用什么样的服务/对象来完成工作。这提高了清晰度、可测试性和可消保真性。

    假设Foo只需要电子邮件服务,但我将整个容器传递给它,并且在代码的某个地方,电子邮件服务从容器中得到解析。在这种情况下,将很难遵循。相反,最好将电子邮件服务直接注入到状态Foo的依赖项中。

    如果Foo需要创建电子邮件服务的多个实例,最好创建并注入一个EmailServiceFactory(通过IoC容器),它将动态创建所需的实例。

    现在,如果我以后想提供不同的电子邮件服务实例,我会在EmailServiceFactory中交换它。如果它创建的所有服务都需要交换(例如,在测试期间),我也可以交换整个工厂。

    因此,以创建一个额外的类(工厂)为代价,我得到了更干净的代码,并且不必担心使用全局静态时可能出现的奇怪错误。此外,当提供模拟用于测试时,我确切地知道它需要什么样的模拟,而不必模拟整个容器的类型。

    这种方法还有一个优点,即现在,当一个模块被初始化时(仅适用于Prism/模块化),它不必注册它向IoC容器提供的所有类型的对象。相反,它可以注册它的ServiceFactory,然后由它提供这些对象。

    需要明确的是,模块的初始化类(实现IModule)仍应在其构造函数中接收应用程序范围的IoC容器,以便提供其他模块使用的服务,但容器不应侵入模块的类。

    最后,我们这里有另一个很好的例子,说明了额外的间接层是如何解决问题的。

        2
  •  14
  •   Ryu    15 年前

    将IOC容器放在流程中的最高级别/入口点,并使用它将依赖项注入到它下面的所有内容中。

        3
  •  6
  •   lcvinny    16 年前

    您可以在容器本身中注册容器,并像其他依赖项属性一样将其注入,如下所示:

    IUnityContainer container = new UnityContainer();
    container.RegisterInstance<IUnityContainer>(container);
    

    private IUnityContainer unityContainer;
    [Dependency]
    public IUnityContainer UnityContainer
    {
        get { return unityContainer; }
        set { unityContainer = value; }
    }
    

    因此,每当解析/构建此类类的实例时,就会注入容器。

    这更灵活,因为它适用于同一应用程序中的多个容器,而单例模式不可能做到这一点。

        4
  •  2
  •   toad    16 年前

    如果您的所有对象都需要对容器的引用,那么您应该重新编写一些代码。尽管仍然比到处调用new更可取,但它仍然分散了在代码中构建对象图的责任。这种用法让我觉得它更像是一个ServiceLocator,而不是IoC容器。

        5
  •  0
  •   t3mujin    16 年前

    另一个选择是使用 CommonServiceLocator ,尽管这可能是一个无意义的间接过程,但您可以使用 ServiceLocator.Current 作为所有类都知道的实例