Главная страница   /   15. MEF (Внедрение зависимостей в .NET

Меню:

  • Знакомство с MEF
  • Управление жизненным циклом
  • Работа с составными компонентами
  • Конфигурирование сложных API

В пяти предыдущих главах вы наблюдали за тем, как можно использовать различные DI-контейнер'ы в качестве средств реализации паттернов и принципов, описанных в остальной части книги. В этой главе мы будем заниматься несколько другим, поскольку Managed Extensibility Framework (MEF – управляемая платформа расширений) в действительности не является DI-контейнер'ом.

Судя по названию, MEF – это фреймворк, предназначенный для решения проблем расширяемости приложений. Целью MEF является подключение к стандартному приложению дополнительных сценариев. Вероятно, Visual Studio 2010 является самым первым и наиболее известным приложением, в котором MEF используется для поддержки плагинов. Но с другой стороны, любое другое приложение, созданное на платформе .NET 4 или Silverlight 4, также может использовать MEF для раскрытия возможностей расширяемости.

Если MEF не является DI-контейнером, то почему тогда на ее рассмотрение мы выделили целую главу? Самая важная причина заключается в том, что MEF настолько похож на DI-контейнер, что вы потратите уйму времени на то, чтобы разобраться, в чем же его отличие от реального DI-контейнера. Поскольку он является частью .NET 4 или Silverlight 4, возможно, использование его в качестве DI-контейнера было бы довольно заманчивым, если бы вы не понимали тонкой границы между ними. Цель этой главы – выявить эти различия для того, чтобы вы могли принять верное решение.

Примечание

Не забывайте, что если вам не интересен MEF и вы уже решили использовать другой DI-контейнер, вы всегда можете пропустить эту главу.

Является ли MEF DI-контейнер'ом?

Вокруг того, является ли MEF DI-контейнером или нет, возникает слишком много путаницы. Если вкратце, то нет, MEF не является DI-контейнером, но у него настолько много общего с "настоящими" DI-контейнерами, что в будущем он может стать полноценным DI-контейнером.

MEF не создавался как DI-контейнер. Его целью является предоставление универсального фреймворка для подключения дополнительной функциональности в стандартные приложения. С точки зрения стандартного приложения, расширение – это неизвестный компонент. Несмотря на то, что расширение, по всей видимости, необходимо для раскрытия определенного интерфейса, это и есть все, что знает о нем приложение. В зависимости от среды разработки в приложении могут присутствовать одно или несколько расширений, или же в приложение может не входить ни одного расширения. Эти MEF отличается от DI-контейнера, в котором мы обычно на этапе компиляции бываем осведомлены обо всех (или о большинстве) его компонентах.

Когда мы используем DI-контейнер в качестве инструмента для компоновки приложения, мы точно знаем, из каких компонентов состоит приложение, и используем эти знания для того, чтобы сконфигурировать контейнер в Composition Root приложения.

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

Традиционный механизм обнаружения расширений заключается в просмотре определенного каталога сборок с целью обнаружения всех классов, реализующих необходимую абстракцию. Однако это не решает той проблемы, которая возникает, когда у самого расширения есть зависимости. С другой стороны, MEF решает именно эту проблему посредством расширенной модели обнаружения, которая для определения потребителей и их сервисов использует атрибуты.

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

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

При рассмотрении внутренней инфраструктуры MEF, оказывается, что процессы обнаружения расширений и компоновки не связаны друг с другом. Это означает, что компания Microsoft может усовершенствовать MEF в направлении настоящего DI-контейнера. С другой стороны, некоторые DI-контейнер'ы обладают столь огромным багажом основанных на соглашениях возможностей, что в будущем могут посягнуться на MEF.

Даже на сегодняшний день MEF имеет столь много общего с DI-контейнерами, что некоторые считают его DI-контейнером, а некоторые отвергают этот факт.

Подсказка

Если вы уже пытались использовать MEF в качестве DI-контейнера и были разочарованы и сбиты с толку, то эта глава объяснит вам, почему так произошло.

Несмотря на то, что, когда MEF зарождался и разрабатывался, возможность использования его в качестве DI-контейнера не имела первостепенной важности, оказывается, его все-таки можно использовать как DI-контейнер. Со временем это стало возможным, хотя и довольно затруднительным. Существует несколько сценариев, при которых имеет смысл использовать MEF в качестве DI-контейнера: в частности, в приложениях, в которых он уже используется для реализации возможностей расширяемости приложения.

Примечание

Общая предпосылка этой главы (непреднамеренно) заключается в том, что использование MEF не принесет нам успешного результата. Это не означает, что MEF делает что-то не так. Это означает, что мы пытаемся заставить MEF сделать то, для чего он не предназначен. Мы пытаемся сделать невозможное.

В этой главе мы рассмотрим, как можно использовать MEF для применения принципов и паттернов, описанных в частях 1-3. На рисунке 15-1 продемонстрирована структура этой главы.

Рисунок 15-1: Эта глава состоит из четырех разделов. Первый раздел знакомит нас с MEF и демонстрирует способы конфигурирования и разрешения компонентов. Следующие три раздела связаны с паттернами применения, которые требуют дополнительного внимания. Их можно прочитать по порядку или же пропустить некоторые из этих разделов и прочитать только те, которые вас интересуют.

Структура главы является отражением структуры всех остальных глав части 4, поскольку я считаю, что это облегчает сравнение различных DI-контейнеров. В случае с MEF это приводит к четырем неравноценным по размеру и важности разделам. Много времени мы потратим на знакомство с MEF для того, чтобы получить полноценное понимание этого контейнера и его API. На рассмотрение механизма управления жизненным циклом выделим только несколько страниц, поскольку в этой области MEF не обладает обширными возможностями. Далее большая часть оставшейся главы отведена на изучение возможностей работы с составными компонентами, а последний раздел снова занимает совсем немного страниц. Первый раздел является предпосылкой остальных разделов, оставшиеся три раздела можно читать независимо друг от друга.

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

Вы можете прочитать эту главу, не читая при этом остальные главы части 4, специально для того, чтобы познакомиться с MEF, или можете прочитать ее совместно с остальными главами части 4, чтобы сравнить MEF с "настоящими" DI-контейнерами. Цель данной главы – показать, как MEF связан с паттернами и принципами, описанными в остальной части книги, и как он их реализует.

15.1. Знакомство с MEF

15.2. Управление жизненным циклом

15.3. Работа с составными компонентами

15.4. Конфигурирование сложных API

15.5. Резюме