Как внедрить зависимость от статического класса в C # - PullRequest
0 голосов
/ 14 сентября 2018

Я делаю простой класс логгера с DI, но у меня есть некоторые проблемы и вопросы.

Проблема есть. Если я сделаю класс регистратора с DI. Я должен использовать это так, как только использую.

var logger = new LogService(new FileLogger());
logger.WriteLine("message");

Я хочу сделать это статическим классом, но нет способа внедрить зависимость конструктором в статический класс.

Итак, я меняю это так.

public static class LogService()
{
    private static readonly ILoggable _logger;
    static LogService()
    {
         _logger = new FileLogger();
    }
}

Я думаю, это так странно. Это не DI ..

Нет ли хорошего способа внедрить зависимость в статический класс?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

Вот пример внедрения логгеров log4net с Unity DI-контейнером с использованием UnityLog4NetResolver расширение:

public class A
{
    readonly ILog log;

    public A(ILog log)
    {
        this.log = log;
    }

    ...
}

...

var container = new UnityContainer();

container
    .AddNewExtension<UnityLog4NetResolver.LogByTypeResolverExtension>();

container.Resolve<A>();

Последнее утверждение эквивалентно new A(LogManager.GetLogger(typeof(A))). Таким образом, каждый класс может иметь регистратор с соответствующим именем, введенным контейнером DI.

Идея была взята из этого пакета . Однако он, похоже, заброшен и не поддерживает последнюю версию Unity.

0 голосов
/ 14 сентября 2018

Внедрение зависимостей, как практика, предназначено для введения абстракций (или швы ) для отделения изменчивых зависимостей. Энергозависимая зависимость - это класс или модуль, который, среди прочего, может содержать недетерминированное поведение или вообще является чем-то, что мы можем заменить или перехватить. Для более подробного обсуждения изменчивых зависимостей см. раздел 1.3.2 этого свободно загружаемого введения из этой книги .

Поскольку ваш FileLogger записывает на диск, он содержит недетерминированное поведение . По этой причине вы ввели абстракцию ILoggable. Это позволяет отделить потребителей от реализации FileLogger.

Однако, чтобы иметь возможность успешно отделить потребителя от его изменчивой зависимости, нам необходимо внедрить эту зависимость в потребителя. На выбор предлагается три общих шаблона:

  • Внедрение в конструктор - Зависимости статически определяются как список параметров для конструктора instance класса.
  • Внедрение свойства - Зависимости вводятся в потребителя через свойства instance , доступные для записи.
  • Внедрение метода - Зависимости вводятся в потребителя как параметры метода.

И Инъекция конструктора, и Инъекция свойства применяются внутри Корень композиции и требуют от потребителя сохранить зависимость в закрытом поле для последующего повторного использования. Для этого необходимо, чтобы конструктор и свойство были членами экземпляра , то есть нестатическими. Статические конструкторы не могут иметь никаких параметров, а статические свойства приводят к анти-шаблону Ambient Context (см. Главу 5.3 этой книги ) и Temporal Coupling . Это затрудняет тестируемость и ремонтопригодность.

Внедрение метода, с другой стороны, применяется вне корня композиции, и оно не сохраняет любую предоставленную зависимость, а просто использует ее. Поэтому внедрение метода может применяться как к экземпляру, так и к статическим методам. В этом случае потребитель метода должен предоставить зависимость. Это, однако, означает, что сама эта зависимость должна быть предоставлена ​​либо с помощью внедрения конструктора, свойства или метода.

Ваш пример статического LogService, который создал FileLogger внутри его конструктора, является отличным примером сильно связанного кода. Это называется анти-паттерном Control Freak (глава 5.1) или вообще может рассматриваться как нарушение DIP . Это напротив DI.

Чтобы предотвратить сильное связывание энергозависимых зависимостей, лучше всего сделать LogService нестатичным и внедрить его энергозависимые зависимости в единственный открытый конструктор.

0 голосов
/ 14 сентября 2018

Почему вы хотите использовать инъекционные зависимости и статический класс?

public static class LogService
{
    private static ILoggable _logger;
    public static ILoggable Logger
    {
        get
        {
             return _logger;
        }
    }
    public static InitLogger(ILoggable logger)
    {
         _logger = logger;
    }
}

И тебе сначала нужно Инициатива, как эта

LogService.InitLogger(new FileLogger());

LogService.Logger.WriteLine("message");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...