如何将依赖项注入静态类

Mas*_*uri 4 c# dependency-injection

我一直在用DI制作简单的记录器类,但是我有一些问题。

这儿存在一个问题。如果我使用DI进行记录器课程。每当我使用它时,都应该这样使用它。

var logger = new LogService(new FileLogger());
logger.WriteLine("message");
Run Code Online (Sandbox Code Playgroud)

我想使其成为静态类,但是没有办法通过静态类中的构造函数注入依赖项。

所以,我这样改变它。

public static class LogService()
{
    private static readonly ILoggable _logger;
    static LogService()
    {
         _logger = new FileLogger();
    }
}
Run Code Online (Sandbox Code Playgroud)

我觉得这很奇怪。这不是DI ..

没有将依赖项注入静态类的好方法吗?

谢谢。

Ste*_*ven 10

作为一种实践,依赖注入旨在引入抽象(或接缝)来消除易失性依赖。易失性依赖项是一个类或模块,除其他外,它可以包含不确定性行为,或者通常是我们可以替换或拦截的类或模块。有关volatile依赖关系的详细讨论,请参见本书的可免费下载的简介1.3.2节

因为您FileLogger写入磁盘,所以它包含不确定的行为。因此,您引入了ILoggable抽象。这样可以使使用者与实现分离FileLogger

为了能够使消费者与其不稳定的依赖关系成功脱钩,我们需要这种依赖关系注入消费者。共有三种常见模式可供选择:

  • 构造函数注入-依赖关系被静态定义为该类的实例构造函数的参数列表。
  • 属性注入-通过可写实例属性将依赖项注入使用者。
  • 方法注入-依赖项作为方法参数注入到使用者中。

构造器注入和属性注入都应用合成根” 内部,并且要求使用者将依赖项存储在私有字段中,以便以后重用。这要求构造函数和属性是实例成员,即非静态的。静态构造函数不能具有任何参数,并且静态属性会导致Ambient Context反模式(请参见本书的第5.3章)和时间耦合。这阻碍了可测试性和可维护性。

方法注入,另一方面,被施加的组合物根,它并没有存储任何提供的相关性,而仅仅使用它。因此,方法注入可以应用于实例方法和静态方法。在这种情况下,方法的使用者必须提供依赖性。但是,这的确意味着必须通过构造函数,属性或方法注入将自身提供给该依赖项。

您在其构造函数内部LogService创建的static的FileLogger示例是强耦合代码的一个很好的示例。这被称为Control Freak反模式(第5.1章),或者通常可以视为违反DIP。这 DI 相反

为了防止易失性依赖关系的强耦合,最好是使它成为LogService非静态的,并将其易失性依赖关系注入其唯一的公共构造函数中。

  • 我想说,关于这些概念的最佳资源是我合着的《依赖注入原则、实践和模式》(https://mng.bz/BYNl)一书。我当然认为它“对大脑友好”,但肯定不适合五岁的孩子。它需要一些软件开发经验。 (3认同)

Tim*_*ang 8

将依赖注入 (DI) 与静态类一起使用是没有意义的。而不是 DI,只需向您的静态类添加一个初始化方法并传入依赖项。

public static class LogService
{
    private static ILoggable _logger;

    public static ILoggable Logger
    {
        get
        {
             return _logger;
        }
    }

    public static void InitLogger(ILoggable logger)
    {
         _logger = logger;
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用记录器,请确保先调用InitLogger()

LogService.InitLogger(new FileLogger());
LogService.Logger.WriteLine("message");
Run Code Online (Sandbox Code Playgroud)