典型的 IoC 容器用法 - 向下传递数据

发布于 2024-08-08 15:22:52 字数 1944 浏览 4 评论 0原文

我最近第一次开始使用 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 容器执行此类操作的最佳实践是什么?

I've recently started using an IoC container for the first time, but I'm not educated on the best practices for using it. More specificaly I'm using Unity in a C# .NET project, and I started using it because it came with Prism.

I use the container to resolve the "top level" objects, and they get the correct objects injected based on the container. However, I can't see the best practice clearly when I have an object with children and children's children, and I need some data from the IoC container all the way down, but not in between. How you'd typically organize the use of IoC container?

Initially I'd think that you'd pass the container everywhere it is needed instead of extracting the needed data from the container on top-level and passing this data on. But then again I get problems when I reach objects which take other specific data in addition to the injected interfaces, and I'd prefer not to inject these through properties or init-methods after resolving the object.

I hope this was clear enough, but let's look at a fictional (and slightly stupid..) example.

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(); 
    }
}

So, this example doesn't really make much sense, but the essence is the same of what I need to do. I have some application commands I pass down the line through my ViewModel classes, because some of them need to be able to trigger commands to display something. I also have common storage, etc. which may be needed for some classes but currently are passed through and stored in middle classes. With only commands it's no big deal if you store commands or container, but would one in a typical IoC-usage pass the IoC container instead, and use this for resolving objects down the line? And what about specific data like the customer name? You can't just pass this in on the Resolve(), so you need to inject that afterwards?

Sorry - this was as short as I was able to make it. Won't require answers of the same length ;-) .. Just; what's the best practice of doing stuff like this with IoC containers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不忘初心 2024-08-15 15:22:52

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

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>(); 

这对你有帮助吗?

I'm not quite sure that I understand your question. But I don't think you should be passing the container around at all. It's much easier to just create a wrapper class for the container. For example:

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;
    }
  }
}

Now you call this everywhere in your code.

IoCContainer.Instance.Resolve<IAwesomeService>(); 

Does this help you?

烟若柳尘 2024-08-15 15:22:52

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

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

I'm not sure if this answers your question, but I would say that a good way to act on an application using the Unity container (also applicable to other IoC engines I think) is:

  • Design your classes so that all the
    required dependencies are specified
    in the constructor. This way you
    don't need to explicitly deal with
    Unity unless you need to create new
    objects.
  • If you need to create new objects
    within your classes, pass the Unity
    container itself in the constructor
    as well (as a reference to
    IUnityContainer), and create all new
    object instances by using the Resolve
    method. Even for objects that are not
    registered and have not dependencies,
    the container will give you a proper
    instance, and later you can decide to register types that were not previously registered, without changing the client code.
  • As for passing explicit values to resolved objects, you can specify concrete injection members when you register types (see the InjectionMembers parameter in the RegisterType class).
少女的英雄梦 2024-08-15 15:22:52

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

请参阅此 答案。

It seems that you need to declare factories for your entities. Resolve factories via constructor injection and pass data values via Create method. All other dependencies must be resolved via factory's constructor.

See this answer.

清晨说晚安 2024-08-15 15:22:52

我将定义一个静态类 IoC,它可以使用特定容器进行初始化,并实现诸如 Resolve、Resolve(...) 之类的方法,这些方法又将实际工作委托给容器实例(您可以将此实例存储在领域或财产)。这样您就不必传递任何内容,只需

IoC.Resolve<SomeType>();

在代码中的任何位置使用即可。

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

I'd define a static class IoC, that can be initialized with a particular container and implement methods like Resolve, Resolve(...), which in turn delegate the actual work to the container instance (you'll store this instance in a field or property). This way you don't have to pass anything around, just use

IoC.Resolve<SomeType>();

anywhere in your code.

Regarding the specific data: some containers will take a parameter and resolve depending on this parameter (Autofac has this kind of feature). Or you can always create a factory class that will have a method that accepts a set of parameters (like customer name) and returns a corresponding object instance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文