Внедрение отражающей зависимости .NET с несколькими контейнерами

#c# #.net #reflection #dependency-injection

#c# #.net #отражение #внедрение зависимостей

Вопрос:

Я относительно новичок в внедрении зависимостей, поэтому, вероятно, в какой-то степени искажаю концепцию. Тем не менее, я пытаюсь достичь чего-то подобного следующему, но не уверен, возможно ли это:

Допустим, у меня есть два контейнера, каждый из которых содержит разные экземпляры зависимости одного и того же типа. Например, каждый из них содержит свой единственный экземпляр MyApplicationContext и MyRequestContext .

Теперь предположим, что у меня есть несколько классов, которые зависят от одного (или обоих) из этих экземпляров. Их не должно волновать, какой из двух контейнеров они используют; им просто требуется экземпляр зависимости для выполнения работы.

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

 public class MyDependableClass{
  protected MyApplicationContext Application {get; set;}
  protected MyRequestContext Request {get; set;}
  public MyDependableClass() {
    Dependencies.Inject(this);
  }
}
  

Однако, AFAIK, нет практического способа определить подходящий контейнер. Я рассматривал возможность регистрации каждого объекта в определенном контейнере (например, container.Register(obj); ), но это было бы трудоемким и не сработало бы, если бы в конструкторе требовались зависимости. В качестве альтернативы вы могли бы проанализировать стек вызовов, чтобы вывести контейнер из зарегистрированного объекта верхнего уровня… не будет работать для асинхронных вызовов и т. Д

Есть идеи?

Пример: у меня может быть несколько классов, которые могут зависеть от экземпляра прокси; давайте назовем это ILogicProxy . Этот прокси-сервер может перенаправлять вызовы либо на локальную логику, либо на удаленную логику на другом компьютере. Кроме того, приложение может устанавливать соединения с несколькими удаленными машинами. Итак … у нас есть потенциально несколько ILogicProxy экземпляров, которые необходимо внедрить в несколько классов… но какой из них куда ведет? Подобное решение могло бы просто использовать простое «внедрение свойства setter», однако это не масштабируется, когда требуется больше зависимостей, поскольку это приведет к тому, что процесс «подключения» станет беспорядочным / подробным.

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

1. Можете ли вы обновить свой вопрос, чтобы объяснить, почему вы считаете, что вам нужно иметь два контейнера. Объясните, чего вы пытаетесь достичь. Это помогает нам понять контекст и, надеюсь, помочь вам больше.

2. Спасибо, Стивен, я добавил пример.

3. какой контейнер вы используете?

4. Я не такой. Я использовал термин «контейнер» для обозначения набора зависимостей.

5. Если вы пишете, container.Register(...) а затем разрешаете компоненты с зависимостями от container , то это контейнер. Это может быть пользовательский контейнер, но это все равно контейнер.

Ответ №1:

Это не относится к нескольким контейнерам. Используйте конфигурацию контейнера для настройки. Если у вас есть большое количество компонентов, зарегистрированных в ILogicProxy интерфейсе, тогда да, вам придется выполнять больше ручной настройки. Но спросите себя, действительно ли эти компоненты должны быть зарегистрированы в одном интерфейсе.

О примере кода:

В идеальном мире каждый из этих надежных классов выполняет статический вызов в своем конструкторе, который, в свою очередь, рефлексивно внедряет зависимости из соответствующего контейнера…

 public class MyDependableClass{
  protected MyApplicationContext Application {get; set;}
  protected MyRequestContext Request {get; set;}
  public MyDependableClass() {
    Dependencies.Inject(this);
  }
}
  

Это расположение службы, а не внедрение зависимостей. Всегда предпочитайте внедрение зависимостей местоположению службы. Старайтесь не зависеть от методов Resolve() или Inject() в ваших компонентах.

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

1. Спасибо Маурисио. Я смутно помню расположение службы со времен моей учебы на Java в университете, и да, я согласен, мой пример больше похож на этот метод. Однако файлы конфигурации являются статическими, что означает, что я не могу создать ассоциации зависимость-> надежные на уровне экземпляра, поскольку я могу создать ассоциацию только на уровне определения. Например. Я хочу ‘instanceA зависит от InstanceB’, а не ‘ClassA зависит от ClassB’.

2. @Lawrence: не могли бы вы подробнее рассказать о «файлах конфигурации являются статическими»? может быть, опубликовать какой-нибудь код?

Ответ №2:

Мне кажется, что вам не нужно несколько контейнеров, но вам нужно создать реализацию ILogicProxy , которая знает, как маршрутизировать. Возможно, вы могли бы реализовать этот тип как оболочку вокруг другой ILogicProxy реализации, например, так:

 public class LogicProxyRouter : ILogicProxy
{
    private readonly ILogicProxy local;
    private readonly ILogicProxy remote;

    public LogicProxyRouter(ILogicProxy local, ILogicProxy remote)
    {
        this.local = local;
        this.remote = remote;
    }

    public void Method(params)
    {
        if (someCondition)
        {
            this.local.Method(params);
        }
        else
        {
            this.remote.Method(params);
        }
    }
}
  

Таким образом, вы можете подключить один экземпляр следующим образом:

 ILogicProxy proxy =
    new LogicProxyRouter(new LocalLogicProxy(), new RemoteLogicProxy());

// Register that instance in your favorite IoC framework
container.RegisterSingle<ILogicProxy>(proxy);
  

Я надеюсь, что это поможет.