Как комбинировать проектируемые компоненты с внедрением зависимостей

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

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

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

  • Поиск услуг

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

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

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

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

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

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


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


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


person Wim Coenen    schedule 30.06.2009    source источник


Ответы (1)


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

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

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

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

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

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

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

person Mark Seemann    schedule 02.07.2009
comment
Если я правильно интерпретирую ваш ответ, вы говорите, что элементы управления не должны использовать какие-либо службы. Я не уверен, что согласен. Например, у меня есть элемент управления, который не отображает текст напрямую, вызывая System.Windows.Forms.TextRenderer. Вместо этого он использует инъекционную службу ITextRenderer (в основном с теми же методами). Это позволяет мне реализовывать причудливые стратегии сокращения, выходящие за рамки того, что предоставляется платформой .NET, сохраняя при этом независимость такого кода от самого элемента управления. - person Wim Coenen; 03.07.2009
comment
Да, я говорю, что элементы управления не должны использовать службы - службы должны использовать элементы управления. Элемент управления не должен делать ничего, кроме визуализации пользовательского интерфейса. Это нормально, что вы можете вводить причудливые стратегии сокращения, но такая логика принадлежит модели (View), а не самому View. Затем вы можете привязать свое представление к свойствам модели, которые производят желаемые значения, вызывая внедренные зависимости. Даже если вам кажется, что вы используете WinForms, посмотрите это для вдохновения: msdn.microsoft .com / ru-ru / magazine / dd419663.aspx - person Mark Seemann; 04.07.2009