Внедрение внутреннего вспомогательного класса при разрешении открытого класса - PullRequest
7 голосов
/ 23 января 2011

У меня есть следующая архитектура, в которой общедоступный класс Service, ссылающийся на внутренний класс Helper, существует в другой сборке:

ApplicationAssembly {
  public class Widget {
    public Widget(ReferencedAssembly.Service service) { ... }
  }
}

ReferencedAssembly {
  public class Service {
    public Service(Helper helper) { ... }
  }
  class Helper { ... }
}

(Я понимаю, что не могу поместить внутренний класс в аргументы конструктора открытого класса - я просто пытаюсь проиллюстрировать шаблон IoC, который я собираюсь выполнить.)

Проблема в том, что ApplicationAssembly не может видеть ReferencedAssembly.Helper, поэтому он не может быть зарегистрирован в моем контейнере IoC (в данном случае Autofac). В результате невозможно разрешить Helper, когда я пытаюсь разрешить Service. Какой мой лучший вариант здесь?

  • Вариант 1: Удалить Helper из конструктора Service и явно добавить его в конструктор. Мне не нравится этот вариант, потому что он как бы нарушает парадигму IoC.

  • Вариант 2: заставить Helper реализовать общедоступный интерфейс IHelper, затем добавить публичный модуль в ReferencedAssembly, который регистрирует Helper как IHelper. Мне не нравится эта опция, потому что она требует ApplicationAssembly, чтобы знать слишком много деталей реализации о Service, и если пользователь забывает зарегистрировать этот модуль при запуске, все ломается.

  • Вариант 3: Создайте открытый статический конструктор на Service, который создает второй контейнер IoC специально для ReferencedAssembly и регистрирует в нем Helper. Удалите Helper из конструктора Service и разрешите его в конструкторе, используя второй контейнер IoC. Это похоже на мой лучший вариант, но требует большего количества «слесарного» кода, чем другие. Я также не большой поклонник публичных статических конструкторов.

  • Вариант 4. Измените мою архитектуру на что-то совсем другое.

1 Ответ

12 голосов
/ 24 января 2011

Способ регистрации внутренних типов в Autofac состоит в том, чтобы включить модуль Autofac Module внутри сборки с внутренними типами и зарегистрировать модуль в контейнере.Поскольку модуль находится в той же сборке, он может настроить ContainerBuilder с внутренними типами.

Я думаю, что лучший вариант - заставить Service реализовать открытый интерфейс, а затем сделать класс Service, которыйу вас сейчас внутренний.Autofac с радостью создаст экземпляр внутреннего класса для предоставления открытого интерфейса.

Другой вариант (чтобы позволить Service получить зависимость от конструктора от внутреннего типа) - сделать конструктор Service внутренним, изатем используйте поиск конструктора при регистрации типа Service:

builder.RegisterType<Service>()
  .FindConstructorsWith(new BindingFlagsConstructorFinder(BindingFlags.NonPublic));
...