Использовать внедрение зависимостей в статический класс

#c# #dependency-injection

#c# #класс #внедрение зависимостей #статический

Вопрос:

Мне нужно использовать внедрение зависимостей в статическом классе.

методу в статическом классе требуется значение введенной зависимости.

Следующий пример кода демонстрирует мою проблему:

 public static class XHelper
{
    public static TResponse Execute(string metodo, TRequest request)
    {
        // How do I retrieve the IConfiguracion dependency here?
        IConfiguracion x = ...;

        // The dependency gives access to the value I need
        string y = x.apiUrl;

        return xxx;
    }
}
  

Комментарии:

1. Вы хотите внедрить конфигурацию значков? Почему не нестатический класс?

2. Да, мне нужно ввести IConfiguration, если я не найду решение, мне придется использовать класс без статического

3. Если бы вы могли это сделать, это было бы странно, и, вероятно, позже потребуется провести рефакторинг. Ваш статический класс не имеет права запрашивать зависимость, это противоречит статичности и основному духу DI

4. У вас также есть возможность использовать метод инъекции public static TResponse Execute(string metodo, TRequest request, IConfiguration conf)

Ответ №1:

В основном у вас есть два варианта:

  1. Измените класс с static на класс экземпляра и предоставьте зависимость с помощью внедрения конструктора.
  2. Предоставьте зависимость общедоступному методу класса посредством внедрения метода.

Вот примеры для каждого варианта.

Вариант 1. Измените класс со статического на класс экземпляра

Измените класс с static на класс экземпляра и предоставьте его IConfiguration с помощью внедрения конструктора. XHelper в этом случае следует вводить в конструктор его потребителей. Пример:

 public class XHelper
{
    private readonly IConfiguration config;
    
    public XHelper(IConfiguration config)
    {
        this.config = config ?? throw new ArgumentNullException("config");
    }

    public TResponse Execute(string metodo, TRequest request)
    {
        string y = this.config.apiUrl;

        return xxx;
    }
}
  

2. Передайте IConfiguration методу Execute через внедрение метода.

Пример:

 public static class XHelper
{
    public static TResponse Execute(
        string metodo, TRequest request, IConfiguration config)
    {
        if (config is null) throw new ArgumentNullException("config");
    
        string y = config.apiUrl;

        return xxx;
    }
}
  

Менее благоприятные варианты

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

Например:

  • Возможно, вы захотите сделать контейнер DI доступным через статический метод и вызвать его изнутри вашего статического класса, но это антишаблон, называемый Service Locator.
  • Вы могли бы разрешить установку зависимостей статического класса через статические свойства для этого класса, но это приводит к антишаблону окружающего контекста.
  • Вы могли бы изменить класс на класс экземпляра, но вместо использования внедрения конструктора используйте внедрение свойств, но это вызывает временную связь, которая является запахом кода.

Комментарии:

1. @Steven Когда будет реализован 1-й вариант, нужно ли нам также добавить этот сервис класса а?

2. @Steven В среде веб-api со вторым сценарием, откуда я могу получить конфигурацию в моем методе контроллера?

3. Вы вводите его через конструктор контроллера.

4. @sridawg то, что вы описываете, называется окружающим контекстом и является антишаблоном .

5. к сожалению, ничего из этого не полезно во многих сценариях.

Ответ №2:

у меня была эта проблема, и я разработал этот пакет nuget: ServiceCollectionAccessorService

репозиторий: ServiceCollectionAccessorService по сути, это статический класс, который имеет доступ к корневой коллекции сервисов, из которой вы можете создать своего провайдера:

 private static LogData GetLogData() => ServiceCollectionAccessor.Services.BuildServiceProvider().GetRequiredService<LogData>();
  

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

Комментарии:

1. Это очень плохая идея. Прежде всего, это реализация антишаблона Service Locator . Однако в вашем примере кода вы создаете контейнер DI снова и снова. Это может вызвать проблемы с производительностью, утечки памяти и нарушенный стиль жизни . Это могло бы сработать в вашей конкретной ситуации, но я бы предостерег кого-либо от использования этого подхода.

2. спасибо за ваш совет, я постараюсь найти лучший способ