Как совместить проектируемые компоненты с внедрением зависимостей - PullRequest
9 голосов
/ 30 июня 2009

При создании проектируемого компонента .NET вы должны предоставить конструктор по умолчанию. Из документации IComponent :

Чтобы быть компонентом, класс должен реализовать интерфейс IComponent и предоставить базовый конструктор, который не требует параметров или одного параметр типа IContainer.

Это делает невозможным внедрение зависимостей через аргументы конструктора. (Могут быть предоставлены дополнительные конструкторы, но дизайнер их игнорирует.) Некоторые альтернативы, которые мы рассматриваем:

  • Сервисный локатор

    Не используйте внедрение зависимостей, вместо этого используйте шаблон локатора службы для получения зависимостей. Кажется, это то, для чего предназначен IComponent.Site. GetService . Я предполагаю, что мы могли бы создать повторно используемую реализацию ISite (ConfigurableServiceLocator?), Которая может быть настроена с необходимыми зависимостями. Но как это работает в контексте дизайнера?

  • Внедрение зависимостей через свойства

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

  • Внедрение зависимостей с помощью метода Initialize

    Это очень похоже на внедрение через свойства, но оно хранит список зависимостей, которые должны быть внедрены в одном месте. Таким образом, список необходимых зависимостей задокументирован неявно, и компилятор поможет вам с ошибками при изменении списка.

Есть идеи, какая лучшая практика здесь? Как ты это делаешь?


edit : Я удалил "(например, WinForms UserControl)", так как я собирался задать вопрос о компонентах в целом. Все компоненты связаны с инверсией управления (см. Раздел 8.3.1 спецификации UMLv2 ), поэтому я не думаю, что «вам не следует вводить какие-либо службы» - это хороший ответ.


edit 2 : Потребовалось немного поиграться с WPF и паттерном MVVM, чтобы наконец "получить" ответ Марка. Теперь я вижу, что визуальный контроль действительно является особым случаем. Что касается использования невизуальных компонентов на поверхностях конструктора, я думаю, что компонентная модель .NET принципиально несовместима с внедрением зависимостей. Похоже, что он разработан вместо шаблона поиска сервисов. Возможно, это начнет меняться с инфраструктурой, которая была добавлена ​​в .NET 4.0 в пространстве имен System.ComponentModel.Composition .

1 Ответ

6 голосов
/ 02 июля 2009

Этот же вопрос долго мучил меня, пока я не понял, что неправильно об этом думаю. AFAIR, единственная причина создания реализации IComponent состоит в том, чтобы предоставить функции времени разработки - нет никакого эффекта времени выполнения реализаций IComponent.

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

Таким образом, ограничение на конструктор - это на самом деле благословение, поскольку оно инструктирует вас переосмыслить свой дизайн. Элемент управления - это независимое от источника данных программное обеспечение, которое отображает и взаимодействует с данными определенным образом. До тех пор, пока эти данные соответствуют определенным интерфейсам и т. Д., Контроль доволен. Как получение данных не имеет значения для Контроля, и не должно быть. Было бы ошибкой позволить Control контролировать, как данные загружаются и изменяются.

В WPF это явно намного яснее, чем в Windows Forms: вы передаете конкретному элементу управления DataContext и привязываете свойства элемента управления к элементам этого DataContext. DataContext (который может быть любым объектом) происходит извне элемента управления; это ответственность или ваш уровень представления.

В Windows Forms вы все еще можете сделать то же самое, назначив контекст данных элементу управления. По сути, это инъекция собственности - просто знайте, что вы не должны внедрять сервисы; Вы должны ввести данные .

Таким образом, я не согласился бы ни с одним из ваших предложений. Вместо этого позвольте элементу управления иметь одно или несколько свойств, которые позволяют назначать данные для элемента управления, и использовать привязку данных для привязки к этим данным. Внутри реализации элемента управления будьте готовы справиться с ситуацией, когда данных нет: это будет происходить каждый раз, когда элемент управления размещается в VS во время разработки. Шаблон Null Object очень полезен для реализации такой устойчивости.

Затем настройте контекст данных из ваших контроллеров. Это способ MVC: Control - это View, но у вас должен быть отдельный Controller, который может создавать экземпляр и назначать Model для View.

...