【问题标题】:How do I instantiate a class with manual dependency injection?如何使用手动依赖注入实例化一个类?
【发布时间】:2018-02-28 16:49:10
【问题描述】:

我有一个可能需要或不需要服务的类,之前通过依赖注入注册,具体取决于用户需要。

他通过静态方法GetInstance(bool) 实例化我的类,如果bool 设置为true,那么我需要调用基于依赖注入的构造函数。如何做到这一点?

public class MyClass {
  private MyClass() {
    // ...
  }

  private MyClass(MyService env) {
    // ...
  }

  public static MyClass GetInstance(bool serviceIsNeeded) {
     if (serviceIsNeeded) {
         /* How to realize the following ?
          * if (!ServiceRegistered<MyService>())
          *     throw new ServiceNotFoundException(...);
          * return InstanciateWithDependencyInjection(typeof(MyClass));
         */
     }
     else
         return new MyClass();
  }
}

例如,在 Java 中,您将 @Inject 标记放在构造函数的顶部,然后像这样实例化您的类:MyClass myClass = getInjector(getContext()).getInstance(MyClass.class)

我正在 C# 和 ASP.NET Core 2 中寻找相同的概念。

【问题讨论】:

  • 这是一种反模式。不要这样做。如果该类需要依赖项,则注入它。如果依赖关系是相对的,那么您可能需要重构代码以使其不是(可能是基类?)。注入依赖项也不应该有开销(反正不多)。为什么注入依赖项而不使用它会有什么不同?这似乎是一种“代码气味”?实例化MyService 是做什么的?
  • @Liam 到时候我会尝试重构它,但不管怎样,即使GetInstance 中没有条件,如何实例化需要DI 的类?
  • 你不应该在你的堆栈中一直使用 DI。框架(简单的注入器,无论你使用的是什么,等等)应该实例化底层类并解决所有依赖关系。这就是您保持松散耦合的方式。一旦你开始使用服务定位器(这几乎就是你在这里谈论的内容)解决依赖关系,你就会引入一个紧密耦合的组件。
  • @Liam 我正在测试该方法,我刚刚发现了 Mocks,所以现在一切都很好,如果你愿意,你可以添加一个总结作为答案,我会接受它,它引导我好办法

标签: c# asp.net-core dependency-injection


【解决方案1】:

Tl;博士,我认为您在这里走错了路。这几乎是Service Locator (anti) pattern


您应该尝试在构建底层类的 DI 框架中自始至终集成 DI,然后其他一切都只接受依赖项。还有一种说法是,“如果你注入一个类而不使用它,这有什么关系?”。提供该类在构造中没有开销(它不应该)只需注入并使用它。

所以你的类应该是这样的:

public class MyClass {

  //inject all the dependencies
  private MyClass(MyService env) {
    // ...
  }


}

漂亮又简单。

服务定位器往往会导致组件耦合过于紧密。例如,在问题中的代码中,您如何对GetInstance 进行单元测试?这很棘手,你不能注入模拟等。

DI 的全部意义在于解耦您的组件以提供更好的灵活性并简化单元测试。

我曾经有一个 UnitTest 项目,它引用了一个虚拟网络应用程序 注册所有必需的服务

看到这不是很好的测试,我想说你的测试很快就会变得臃肿且难以维护。使用模拟引擎等很容易测试上述内容。如果您更改x,您不希望它影响y 的测试。

【讨论】:

    【解决方案2】:

    我会保持 MyClass 清晰,并将依赖项放在构造函数中。如果构造函数无法解决此依赖关系,那么我将创建手动创建对象的工厂类。像这样的:

    public class MyClassFactory{
    
        public MyClass Create(){
            // insetead of manualy creating depenedecy service locator can be 
            // used
            return new MyClass(new MyService());
        }
    }
    
    public class MyClass{
    
        public MyClass(MyService myService){}
    }
    
    public class MyService {
    
    }
    

    【讨论】:

    • 这不是dependency injection at all anymore。你如何对MyClass 进行单元测试?如果 MyService 也有依赖项怎么办?如果这些依赖关系发生变化怎么办?
    • 你仍然对 MyClass 进行单元测试,它没有改变。 MyClass 具有构造函数依赖项。它可以通过 DI 或手动注入(如示例中)。在工厂中,您可以使用服务定位器或手动进行,这取决于您。回答你的问题是使用 DI,不要手动连接依赖项。但显然需要使用服务定位器(或手动连接),因此通过这些方法,您可以清理 MyClass,并使用工厂创建对象并获取依赖项。
    猜你喜欢
    • 2017-11-11
    • 1970-01-01
    • 2020-10-13
    • 2011-04-19
    • 1970-01-01
    • 2021-08-25
    • 2018-02-11
    • 2015-08-05
    • 2022-01-01
    相关资源
    最近更新 更多