2012-05-30 2 views
6

В моем приложении Prism контейнер MEF доступен из класса Bootstrapper через свойство Container.Почему MEF-контейнер недоступен в модулях?

Но это не из модуля класса (IModule). Я могу импортировать контейнер только через IServiceLocator.

Почему? Я подумал, что имеет смысл использовать общий интерфейс для конкретных технологий, но руководство Prism 4.1 просит нас не использовать IServiceLocator (в Considerations for Using IServiceLocator).

ответ

6

Я думаю, что это соответствует не Призмам или MEF, а принципу инжекций зависимостей и лучшим практикам в целом. (Да, я завязываю, что MEF не является контейнером DI, но здесь он используется почти как контейнер DI, поэтому я предполагаю использовать те же методы здесь).

В передовой практике DI (this книга очень круто, я настоятельно рекомендую) это хорошо, чтобы иметь такие шаги в DI «рабочий процесс»:

  • регистр все необходимые типы (в Prism - по Загрузчик. ConfigureCatalog метод())
  • решительность корневой объект - метод (со всеми вложенными объектами в Prism. по Bootstrapper.CreateShell())
  • использовать ваш корневой объект
  • релиз вы корневой объект

В идеале вы НЕ должны использовать контейнер DI больше. Ваш код не должен знать о существовании контейнера DI (с этой стороны Unity действительно является контейнером DI, потому что вы можете написать код, который не знает об использовании контейнера DI). Если ваш код знает об этом - он задерживает контейнер DI, и это плохо.

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

[ModuleExport(typeof(YourModule))] 
public class YourModule : IModule 
{ 
    public static CompositionContainer CompositionContainer; 

    [ImportingConstructor] 
    public void YourModule(CompositionContainer container) 
    { 
     this.CompositionContainer = container; 
    } 
} 

ли не забудьте зарегистрировать свой контейнер MEF непосредственно в вашем Boostrapper:

public class YourBootstrapper: MefBootstrapper 
{ 
    protected override CompositionContainer CreateContainer() 
    { 
     var container = base.CreateContainer(); 
     container.ComposeExportedValue(container); 
     return container; 
    } 
} 
+1

, в то время как я согласен с лучшими практиками, документация призмы четко указывает, что вы можете использовать метод Initialize вашего метода, а также «Зарегистрировать общие службы с контейнером для инъекций приложения». http://msdn.microsoft.com/en-us/library/gg405479%28v=pandp.40%29.aspx – Console

+2

Если мы не должны знать о контейнере, то как модули могут регистрировать новые общие службы? – Benjamin

+0

Указанный 'ComposeExportedValue' является методом расширения в' System.ComponentModel.Composition.AttributedModelServices' – jan

0

Обратите внимание, что я использую более старую версию Prism и что я использую ее с UnityContainer, но должны применяться те же принципы.

Определите свой класс модуля, чтобы принять контейнер в конструкторе.

Вот пример использования Unity:

public class Module : IModule 
{ 
    public static IUnityContainer Container; 

    public Module(IUnityContainer container) 
    { 
     Container = container; 
    } 
} 

Если определить конструктор, который принимает контейнер, он будет вызван методом ApplicationBootstrapper.Run().

Я проверил с конструктором без параметров по умолчанию и конструктором перегрузки, который принимает контейнер, а второй конструктор был вызван.

Я также проверил наличие только конструктора по умолчанию и вызвал его. Я бы предложил вам изменить свой конструктор, чтобы добавить параметр, принимающий контейнер.

Наличие контейнера в вашем классе модулей позволит вам регистрировать типы в методе Initialize.

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

+0

Я пытался это сделать. MEF использует тип CompositionContainer вместо IUnityContainer Unity. Но мой конструктор с параметром, набранным CompositionContainer, не выполняется. –

+0

@reito: У вас также есть конструктор по умолчанию и как вы называете метод запуска ApplicationBootstrapper? – Gilles

+0

У меня больше нет конструкторов, только этот. Метод запуска Bootstrapper вызывает метод OnStartup моего класса Application. –

Смежные вопросы