Является ли MEF делом по принципу «все или ничего»?

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

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

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

Теперь я перехожу к целевому приложению, которое уже описал. И это часть нескольких плагинов, которая немного беспокоила.

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

В идеале я мог бы взять свой существующий загрузчик плагинов и использовать его как есть, полагаясь на MEF для разрешения разделяемой библиотеки. Проблема в том, что я не могу заставить MEF загружать их (т.е. я получаю исключение CompositionException при вызове ComposeParts ()), если я также не использую MEF для загрузки плагина. И если я сделаю это, ну ... тогда мне нужно знать, как отслеживать их по мере их загрузки, чтобы пользователь мог выбрать один из списка плагинов.

Какой у вас был опыт попыток сочетать и сочетать эти подходы?


person Dave    schedule 20.04.2010    source источник


Ответы (1)


MEF разработан, чтобы вы могли легко загружать сборки плагинов. Если у вас есть контроль над плагинами (я имею в виду, что вы можете добавлять атрибуты экспорта MEF), тогда нет необходимости хранить собственный загрузчик плагинов, который использует отражение. MEF сделает все это за вас.

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

Чтобы добавить плагин, который вы загрузили с вашим собственным кодом, в контейнер MEF, вы можете использовать ComposeExportedValue следующим образом:

container.ComposeExportedValue<IPlugin>(selectedPlugin);

edit: Я понимаю, что вы имеете в виду под "все или ничего". Ваша проблема в том, что для того, чтобы иметь возможность импортировать детали с помощью MEF, вам также необходимо создать объект с помощью MEF. Затем эта проблема переходит к объекту, который обычно создавал этот объект, и т. Д. Вплоть до корня приложения.

Чтобы избежать этого эффекта «все или ничего», вы можете пойти на компромисс, выставив контейнер MEF как глобальную переменную (т. Е. Статическое поле). Таким образом, классы могут получить доступ к контейнеру MEF и извлечь из него экспорт, например вызывая Program.Container.GetExportedValue<MyDependency>() в конструкторе.

edit2: если у вас есть объект, созданный не с помощью MEF, его можно добавить в контейнер двумя способами.

Первый - позвонить container.ComposeExportedValue<IMyContractType>(myObject);.

Второй - вернуть объект в средстве получения свойства, а затем пометить само свойство атрибутом [Export (typeof (SomeType))].

person Wim Coenen    schedule 20.04.2010
comment
Отлично, я рад, что моя текущая реализация в точности совпадает с вашей, если использовать имена, указанные в интерфейсе плагина. Он отлично работает. Но все же - это вроде все или ничего. Например, по мере того, как я все больше и больше конвертирую в MEF, я нахожу все больше и больше нулевых ссылок. И это имеет смысл, потому что такому количеству модулей требуются разделяемые библиотеки, и поэтому очевидно, что они также должны быть загружены MEF для разрешения зависимостей. Я не уверен, почему я ожидал иначе - я думаю, это потому, что MEF кажется таким волшебным, и вы знаете, как это происходит. :) - person Dave; 21.04.2010
comment
Похоже, вы прокомментировали мой ответ до того, как я его отредактировал. Я попытался вернуться к исходному состоянию, но, видимо, исправления не сохраняются, если они были сделаны достаточно быстро после публикации ответа: - / - person Wim Coenen; 21.04.2010
comment
@Wim: спасибо за обновления вашего ответа! На самом деле я собираюсь использовать MEF как замену загрузчику плагинов. А для тех, кто не загружен в каталог, я попробую ваш метод, но я думал, что есть метод AddPart, который вы используете для добавления в контейнер? - person Dave; 21.04.2010
comment
@Wim: Это как если бы мы играли здесь в теги постов! :) Спасибо за ответ, я думаю, вы понимаете, о чем я говорю, говоря все или ничего! Итак, да, я думаю, я мог бы сделать что-то вроде того, что вы предлагаете, с контейнером MEF, но не могли бы вы использовать что-то еще для решения этой проблемы, например CSL? - person Dave; 21.04.2010
comment
@Dave: глобальный доступ к контейнеру MEF по сути превращает его в локатор сервисов. У Common Service Locator просто есть то преимущество, что вы помещаете абстракцию между вашим кодом и контейнером, так что вы не получаете повсюду прямую зависимость от MEF. Это может быть важно, если ваш код нужно использовать с другими контейнерами и приложениями IoC. - person Wim Coenen; 21.04.2010
comment
@Wim: Я думал, что использование CSL было одним из многих возможных способов сделать MEF глобально доступным. Или, если я не заботился о привязке себя к конкретному контейнеру IoC, я мог бы использовать Unity для получения контейнера MEF, верно? Нужно больше прочитать об этом. Это довольно сбивает с толку из-за всех доступных вариантов, но когда-нибудь я доберусь до них. - person Dave; 21.04.2010