IoC / DI в лице winforms и другого сгенерированного кода

При использовании внедрения зависимостей (DI) и инверсии управления (IoC) объекты обычно имеют конструктор, который принимает набор зависимостей, необходимых для правильного функционирования объекта.

Например, если у меня есть форма, которая требует, чтобы служба заполняла поле со списком, вы можете увидеть что-то вроде этого:

// my files
public interface IDataService {
    IList<MyData> GetData();
}

public interface IComboDataService {
    IList<MyComboData> GetComboData();
}

public partial class PopulatedForm : BaseForm {
    private IDataService service;
    public PopulatedForm(IDataService service) {
        //...
        InitializeComponent();
    }
}

Это нормально работает на верхнем уровне, я просто использую свой контейнер IoC для разрешения зависимостей:

var form = ioc.Resolve<PopulatedForm>();

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

// generated file: PopulatedForm.Designer.cs
public partial class PopulatedForm {
    private void InitializeComponent() {
        this.customComboBox = new UserCreatedComboBox();
        // customComboBox has an IComboDataService dependency
    }
}

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

Одним из решений является передача зависимостей каждого дочернего компонента в PopulatedForm , даже если они могут не понадобиться напрямую, например, с IComboDataService , требуемым UserCreatedComboBox . Затем я должен убедиться, что зависимости предоставляются через различные свойства или методы установки. Тогда мой конструктор PopulatedForm может выглядеть следующим образом:

public PopulatedForm(IDataService service, IComboDataService comboDataService) {
    this.service = service;
    InitializeComponent();
    this.customComboBox.ComboDataService = comboDataService;
}

Другое возможное решение - использовать конструктор no-args для выполнения необходимого разрешения:

public class UserCreatedComboBox {
    private IComboDataService comboDataService;
    public UserCreatedComboBox() {
        if (!DesignMode && IoC.Instance != null) {
            comboDataService = Ioc.Instance.Resolve<IComboDataService>();
        }
    }
}

Ни одно из решений не является особенно хорошим. Какие шаблоны и альтернативы доступны для более эффективной обработки внедрения зависимостей перед лицом сгенерированного кода? Мне бы хотелось увидеть как общие решения, такие как шаблоны, так и специфические для C #, Winforms и Autofac.

16
задан Kaleb Pederson 11 February 2011 в 22:13
поделиться