【问题标题】:Typical IoC container usage - passing data down the line典型的 IoC 容器使用 - 向下传递数据
【发布时间】:2009-10-23 10:53:16
【问题描述】:

我最近第一次开始使用IoC 容器,但我没有受过有关使用它的最佳实践的教育。更具体地说,我在 C# .NET 项目中使用Unity,我开始使用它是因为它附带了Prism

我使用容器来解析“顶级”对象,它们会根据容器获得正确的对象注入。但是,当我有一个带有孩子和孩子的孩子的对象时,我无法清楚地看到最佳实践,并且我需要来自 IoC 容器的一些数据,但不是介于两者之间。您通常如何组织 IoC 容器的使用?

最初,我认为您应该将容器传递到需要它的任何地方,而不是从顶层容器中提取所需的数据并传递这些数据。但是,当我到达除了注入接口之外还获取其他特定数据的对象时,我又遇到了问题,我不希望在解析对象后通过属性或初始化方法注入这些。

我希望这已经足够清楚了,但是让我们看一个虚构的(而且有点愚蠢..)的例子。

class Employee
{
    private ICommands _commands; 
    priate List<Customer> _customers = new List<Customer>(); 
    public Employee(ICommands commands)
    {
        _commands = commands; 
    }
    public void AddCustomer(string customerName)
    {
        var customer = new Customer(customerName, _commands); 
        _customers.Add(customer); 
    }
}

class Customer 
{
    private string _name; 
    private ICommands _commands; 
    priate List<Case> _cases = new List<Case>(); 
    public Customer(string, name, ICommands commands)
    {
        _name = name; 
        _commands = commands; 
    }
    public void AddCase()
    {
        var case = new Case(_commands); 
        _cases.Add(case); 
    }
}

class Case    {
    private ICommands _commands; 
    public Customer(ICommands commands)
    {
        _commands = commands; 
    }
    public void TriggerCommands()
    {
        _command.TriggerSomething(); 
    }
}

所以,这个例子并没有多大意义,但本质和我需要做的一样。我通过 ViewModel 类传递了一些应用程序命令,因为其中一些需要能够触发命令以显示某些内容。我也有公共存储等,某些类可能需要,但目前通过并存储在中间类中。仅使用命令,如果您存储命令或容器并没有什么大不了的,但是在典型的 IoC 用法中,是否会改为传递 IoC 容器,并使用它来解析对象?那么客户姓名等特定数据呢?你不能只在 Resolve() 上传递它,所以你需要在之后注入它?

抱歉 - 这是我能做到的最简短的。不需要相同长度的答案;-) .. 只是;用 IoC 容器做这样的事情的最佳实践是什么?

【问题讨论】:

    标签: c# .net unity-container ioc-container


    【解决方案1】:

    我不太确定我是否理解您的问题。但我认为你根本不应该传递容器。为容器创建一个包装类要容易得多。例如:

    public class IoCContainer
    {
      private static ContainerType = null;
    
      public static ContainerType Instance 
      {
        get 
        {
          if (_container == null)
          {
            string configFileName = ConfigurationManager.AppSettings[ConfigFileAppSettingName];
            _container = new WindsorContainer(new XmlInterpreter(configFileName));
          }
    
          return _container;
        }
      }
    }
    

    现在您在代码中的任何地方都调用它。

    IoCContainer.Instance.Resolve<IAwesomeService>(); 
    

    这对你有帮助吗?

    【讨论】:

    • 谢谢。我相信这会有所帮助。这被认为是最佳实践吗?这意味着我不必通过无论如何都不会使用它的类传递任何东西 - 这是一件好事..!
    • 将尝试像这样的静态类解决方案。感谢您的帮助!
    • -1... 好意,但你不应该有单例容器。事实上,我认为你根本不应该有单例......见devtrends.co.uk/blog/…devtrends.co.uk/blog/…
    【解决方案2】:

    我不确定这是否能回答您的问题,但我想说使用 Unity 容器(我认为也适用于其他 IoC 引擎)对应用程序执行操作的好方法是:

    • 设计您的类,以便所有 指定了所需的依赖项 在构造函数中。这样你 不需要明确处理 Unity 除非你需要创建新的 对象。
    • 如果需要创建新对象 在您的课程中,通过 Unity 容器本身在构造函数中 以及(作为参考 IUnityContainer),然后创建全新的 对象实例使用Resolve 方法。即使对于不是 已注册且没有依赖项, 容器会给你一个适当的 实例,稍后您可以决定注册以前未注册的类型,而无需更改客户端代码。
    • 至于将显式值传递给已解析的对象,您可以在注册类型时指定具体的注入成员(参见RegisterType 类中的InjectionMembers 参数)。

    【讨论】:

    • 这是我试图实现的目标,直到我遇到使用 Resolve 创建对象时如何将显式值传递给构造函数的问题。但是会查看您提到的 InjectionMembers 参数。然而,我已经阅读了一些地方的建议,反对在任何需要的地方传递 IoC 容器,但你是说这样可以吗?
    • 我的观点是:如果您的整体应用程序设计基于通过 IoC 容器获取所有对象,那么有什么比以相同方式获取 IoC 容器本身更连贯的呢?
    【解决方案3】:

    您似乎需要为您的实体声明工厂。通过构造函数注入解析工厂并通过 Create 方法传递数据值。所有其他依赖项都必须通过工厂的构造函数来解决。

    请参阅this 答案。

    【讨论】:

      【解决方案4】:

      我会定义一个静态类 IoC,它可以使用特定的容器进行初始化,并实现像 Resolve、Resolve(...) 这样的方法,这些方法又将实际工作委托给容器实例(您将存储这个字段或属性中的实例)。这样你就不必传递任何东西,只需使用

      IoC.Resolve<SomeType>();
      

      代码中的任何位置。

      关于具体数据:有些容器会带一个参数,根据这个参数解析(Autofac有这种特性)。或者,您始终可以创建一个工厂类,该类将具有一个接受一组参数(如客户名称)并返回相应对象实例的方法。

      【讨论】:

      • 谢谢。似乎使用静态 IoC 类是一种流行的选择。听起来很合理。
      • 查看我对卡尔回答的评论。
      猜你喜欢
      • 2013-01-12
      • 1970-01-01
      • 2011-11-28
      • 2015-09-29
      • 2011-07-01
      • 2010-11-15
      • 2023-03-17
      • 1970-01-01
      • 2021-04-26
      相关资源
      最近更新 更多