繁体   English   中英

与使用DI容器相比,使用new运算符创建对象/依赖关系

[英]Using the new operator to create objects/dependencies vs. using DI containers

通过构造函数注入手动连接依赖项有什么不好的地方,而使用DI容器( container.Resolve<T>() )有什么不好的地方呢?

我的意思是,除了事实之外,每次需要创建依赖对象并将其提供所有依赖项时,您都必须键入一些按键。

实际上,拥有像DI容器这样的中央注册表可以使您更加困惑,并且无法控制您。

我有一个问题和另一个问题(以下),有一段时间了,但是我猜Mark Seemann的文章“ Service Locator”是一个反模式 ,我终于在这里输入了这个问题。

所以,我的另一个问题是:

如果有一个依赖项本身需要一些动态的(例如用户提供的)输入来构造它,该怎么办? 像这样说:

class Dependency : IDependency
{
  public Dependency(string userInput) { }
}

class Dependent
{
    IDependency _dependency;

    void DoSomething()
    {
      var container = new MyFavoriteContainerFromTheMarket();

      Console.Write("Hey, user. How are you feeling?");
      var userInput = Console.ReadLine();

      // Do DI containers have overloads for Resolve instead of for Register
      // that accept parameters to be passed to constructors?
      // In other words, what if I don't know the constructor parameter
      // value at the time of registration of the dependency but only
      // get to know it just before I have to resolve/instantiate the
      // dependency? Do popular DI containers of today have overloads
      // for that? I assume they must
      _dependency = container.Resolve<IDependency>(userInput);
    }
}

总的来说,难道不觉得DI Containers会失去您的控制权吗? 在某些情况下手动连接依赖关系不是很好吗?

当然,我知道有时候这很容易,并且可以节省您的键入时间,并且可以创建一个更简洁,更简洁的代码段,但是将它们混合在一起-某些依赖项由容器管理,而有些则由您自己手动提供-所有这些都使它变得混乱,并迫使您记住哪一个是哪个,从而使维护更加困难,您是否同意?

更新资料

等一下。 我只是意识到我的整个例子很复杂。 我本打算在main()中从客户端代码调用Resolve。 我最初应该在这个问题上发布的代码应该是这样的:

class Dependency : IDependency
{
  public Dependency(string userInput) { }
}

class Dependent
{
    IDependency _dependency;

    public Dependent(IDependency dependency)
    {
      _dependency = dependency;
    }

    public void DoSomething()
    {
    }
}

class Program
{
  public static void Main(string[] args)
  {
      var container = new MyFavoriteContainerFromTheMarket();

      container.Register<IDependency>(new Dependency(/* I want this to come later */));

      container.Register<Dependent>(new Dependent(), 
       new ConstructorInjection<IDependency>());

      Console.Write("Hey, user. How are you feeling?");
      var userInput = Console.ReadLine();

      // It appears I can't do this as it makes perfect sense
      // to have the whole tree of dependencies known at the time
      // of registration.
      var dependent = container.Resolve<Dependent>(userInput);

      dependent.DoSomething();
  }
}

我不知道该更新对先前的讨论有何影响。 好像有些白痴(我)在问之前没有想过这个问题。 问这个问题本身就得出了正确的答案,@ Maarten确认了这个答案,并正在尝试帮助我。

抱歉,@ Maarten。 我浪费了你的时间。 :-)

您不应尝试通过调用容器来解析实例。 您应该使用构造函数注入来注入依赖项。 马克·西曼(Mark Seeman)将此称为“不叫容器,让它叫你”

要解决创建带有运行时值的注入类型实例的问题,请使用abstract factory

因此,您的示例可以这样解决:

class Dependency : IDependency
{
  public Dependency(string userInput) { }
}

interface IDependencyFactory {
    IDependency Create(string userInput);
}

class DependencyFactory: IDependencyFactory {
    IDependency Create(string userInput) {
        return new Dependency(userInput);
    }
}

class Dependent {
    public Dependent(IDependencyFactory factory) {
        // guard clause omitted
        _factory = factory
    }

    private readonly IDependencyFactory _factory;

    void DoSomething() {
        // Do not call the container, let it call you.
        // So no container usage here.
        //var container = ...

        Console.Write("Hey, user. How are you feeling?");
        var userInput = Console.ReadLine();

        var dependency = _factory.Create(userInput);
        // There you go!
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM