#c# #dependency-injection #inversion-of-control #ioc-container #mef
#c# #внедрение зависимости #Инверсия контроля #ioc-контейнер #mef
Вопрос:
Обновить
По мере того, как я пытался заставить MEF работать во всем моем приложении, я все чаще сталкиваюсь с местами, где я просто не понимаю, почему он автоматически не создает мою библиотеку, когда я этого ожидаю. Я думаю, все это возвращается к тому, что говорил Рид о необходимости использования MEF для создания всего. Итак, прямо сейчас у меня есть класс чтения XML, которому необходимо использовать мои CandySettings, но даже при том, что его свойство ICandySettings имеет атрибут [Import], оно не импортируется. Сначала я обнаружил, что [Import] не работает со статикой, поэтому я изменил это. Но после этого это все равно не сработало. Я думаю, это потому, что я вручную создаю объект XML reader, а вместо этого MEF хочет, чтобы я [импортировал] XML reader… это означает, что теперь у меня также должен быть интерфейс для этого.
Это почти как использование IoC (или, по крайней мере, для MEF), это все или ничего. Вы не можете просто произвольно использовать его здесь и там, потому что в конечном итоге любой класс, в который вы хотите внедрить свойства, также должен быть создан MEF.
Пожалуйста, поправьте меня, если я ошибаюсь!
Оригинальное сообщение
Что ж, пока все не так плохо. Но у меня действительно есть вопросы после того, как Рид указал мне на MEF как на потенциальную альтернативу IoC (и пока это выглядит довольно неплохо).
Рассмотрим следующую модель: текст alt http://bit.ly/9W0sHt
Как вы можете видеть, у меня есть приложение, и это приложение использует плагины (упс, пропустил эту ассоциацию!). И приложение, и плагины требуют использования объекта типа CandySettings, который находится в еще одной сборке.
Сначала я попытался использовать метод ComposeParts в MEF, но единственный способ заставить это работать — сделать что-то подобное в коде плагина.
var container = new CompositionContainer();
container.ComposeParts(this, new CandySettings());
Но это не имеет никакого смысла, потому что зачем мне создавать экземпляр CandySettings в плагине? Это должно быть в приложении. Но если я добавлю это в код приложения, то плагин волшебным образом не поймет, как добраться до ICandySettings, хотя я использую [Import] в плагине и [Export] в CandySettings. РЕДАКТИРОВАТЬ (вероятно, потому, что я должен вызывать ComposeParts() из приложения, а затем передавать ему плагин?)
Способ, которым я это сделал, заключался в использовании DirectoryCatalog MEF, потому что это позволяет плагину при создании сканировать все сборки в текущей папке и автоматически импортировать все, что помечено атрибутом [Import]. Итак, это выглядит примерно так, и потенциально в каждом плагине:
var catalog = new DirectoryCatalog(".");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
Это в целом отлично работает, но я не могу не думать, что MEF предназначался для использования не так?
Комментарии:
1. Я припоминаю, что при использовании MEF существовали некоторые реальные ограничения и что его предполагалось использовать для таких приложений, как visual studio и так далее, и поэтому вы должны сначала убедиться, что ваш дизайн соответствует их предположениям. В основном сказано, что это «не для всех». codebetter.com/blogs/glenn.block/archive/2009/08/16 /…
2. Я думаю, что все получится хорошо, но это одна из тех вещей, которые я привык ожидать от того, чтобы стать .NET-программистом сейчас. Существует так много способов освежевать кошку, и, по сути, единственный способ, которым вы когда-либо поймете это, — попробовать несколько вариантов. На данный момент я реализовал свой код в MEF и Unity, и оба будут работать, хотя я все еще не уверен, что способ, которым я сделал это в любом фреймворке, на 100% правильный.
3. Можете ли вы добавить сообщение об ошибке, которое вы получаете от
ComposeParts
, код, который вы используете для инициализации вашего контейнера, и код, который вы используете для экспорта / импорта?4. @Daniel: хорошо, я снова пересмотрел свой вопрос. спасибо, что посмотрели на это!
5. Похоже, у вас отмечены два типа
[Export(typeof(IError))]
. Если это так, то композиция не знает, какой из них использовать при создании плагина. Вы должны начать задавать новые вопросы для новых вопросов, чтобы ответы были правильно связаны. Этот становится слишком длинным, чтобы быть полезным для новых людей.
Ответ №1:
«Хитрость» здесь в том, что вы хотите, чтобы MEF создавал ваши плагины для вас.
Способ, которым вы это сделаете, заключается в том, чтобы ваше приложение составляло само себя с указанными типами плагинов:
class PluginRepository
{
[ImportMany(typeof(IPlugin))]
IEnumerable<IPlugin> Plugins { get; set; }
}
Если вы сделаете это и попросите MEF составить ваш класс «repository», MEF создаст объекты. Затем он автоматически создаст их по мере их создания, так что ICandySettings
они будут скомпонованы без вашего вмешательства.
Вам нужно только вручную «скомпоновать» объект, если MEF не создает его для вас.
Комментарии:
1. Хорошо, я попробую, спасибо! Если это работает в тестовом приложении, то вероятный конечный результат в реальном приложении — заменить мой загрузчик плагинов (тот, который в настоящее время использует отражение) кодом, подобным вашему, верно?
2. @Dave: Да. На самом деле вам вообще не нужно использовать отражение. MEF делает это чрезвычайно простым, очень надежным и очень коротким по коду….
3. @Reed: Хорошо, итак, мое приложение [импортировало] интерфейс моего плагина. Мое приложение также использует каталог DirectoryCatalog для поиска всех импортированных сборок. Мой плагин [импортирует] ICandySettings и моя библиотека CandySettings экспортирует с помощью атрибута [Export(typeof(ICandySettings))]. Я прошелся по коду и в приложении подтвердил, что будут созданы экземпляры объекта CandySettings и объекта Plugin. Но конструктору плагина нужны настройки CandySettings, и на этапе построения настройки CandySettings не разрешаются … это ограничение или вы думаете, что я подключил что-то неправильно? Я получаю исключение null.
4. @Reed: Просто ради интереса я пошел дальше и перенес использование CandySettings на период после создания плагина, и теперь это работает! Итак, я предполагаю, что MEF имеет то же ограничение, что и Unity, в том смысле, что вы не можете ожидать, что зависимости свойств будут внедрены в конструктор. Я полагаю, мне, вероятно, следует подумать об изменении этого на внедрение конструктора?
5. @Dave: Да. С MEF вы можете заставить конструктор использовать [ImportingConstructor] и просто использовать ICandySettings в качестве параметра. Это заставляет MEF сначала создавать CandySettings и передавать его конструктору для вас.