2014-10-21 2 views
1

в приложении WPF Я использую Caliburn Micro для MVVM шаблон ... Я хочу попробовать еще IoC и хотите использовать большую часть существующего кода ...SimpleInjector и [Экспорт атрибут объявления]

В моей приложение я определил все экспортируемый класс с помощью атрибута, как

[Export(typeof(ITaggable))] 
[Export(typeof(CorporateActionViewModel))] 
[Export(typeof(IScreen))] 
public class CorporateActionViewModel :... 

Как я могу зарегистрировать их, не делая вручную

ContainerInstance.Register<ITaggable, CorporateActionViewModel>(); 
ContainerInstance.Register<IScreen, CorporateActionViewModel>(); 
ContainerInstance.Register<CorporateActionViewModel, CorporateActionViewModel>(); 

Другой вопрос относительно отложенной инициализации ... I'v e читать here как зарегистрировать ленивый ... но мне нужно вызвать Container.Verify() или нет?

Благодаря

ответ

2

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

Простой инжектор не нуждается в использовании атрибутов для поиска классов, которые вы хотите зарегистрировать. На самом деле это один из design principles экипажа простого инжектора.

Вы можете легко (ну и легко ... в зависимости от вашего текущего дизайна) ... удалить атрибут, если вы будете следовать принципам SOLID для ваших режимов просмотра (и соответствующих представлений).

Если мы возьмем типичное приложение LOB, где мы имеем кучу объектов в базе данных, мы могли бы разделить наш дизайн ViewModel/представления в этих общих интерфейсах, которые ваши ViewModels будут осуществлять (по одному Offcourse):

//for a typical datagrid view of your entities with e.g. Add, Edit and Delete button 
IWorkspace<TEntity>; 

//for a typical edit view for one entity (including possible child entities) 
IEditEntity<TEntity>; 

//for choosing a specific foreign entity type from your edit view 
//e.g. your editing an order and need to specify the customer 
IChooseEntity<TEntity> 

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

Вы можете очень легко зарегистрировать эти типы с простым Injector использованием batch registration так:

container.RegisterManyForOpenGeneric(
    typeof(IChooseEntityViewModel<>), Assembly.GetExecutingAssembly()); 

В качестве бонуса этой конструкции вы можете обернуть ваши ViewModels с одним или несколькими декораторами, которые могут быть использованы для некоторых реальных MVVM, например, найти свой вид, привязать его к модели просмотра и показать вид в окне/странице и т. Д. Если вы хотите больше узнать о декораторах, в сочетании с простым инжектором, вы можете найти интересные статьи here (не забывайте, различные ссылки).

2

Этот запрос будет найти все виды, отмеченные ExportAttribute

private IEnumerable<Type> GetExportedTypes() 
{ 
    return from assembly in AppDomain.CurrentDomain.GetAssemblies() 
      from type in assembly.GetTypes() 
      where Attribute.IsDefined(type, typeof(ExportAttribute)) 
      select type; 
} 

И этот запрос будет найти все услуги, опубликованные для типа с использованием ExportAttribute

private IEnumerable<Type> GetServicesFromType(Type type) 
{ 
    return from attribute in Attribute 
       .GetCustomAttributes(type, typeof(ExportAttribute)) 
      select ((ExportAttribute)attribute).ContractType; 
} 

Эти запросы могут быть использовали что-то вроде этого

var container = new Container(); 

foreach(var type in GetExportedTypes()) 
{ 
    foreach (var service in GetServicesFromType(type)) 
    { 
     container.Register(service, type); 
    } 
} 

container.Verify(); 

Что касается вашего вопроса относительно Verify()? Никогда не обязательно звонить Verify, но это всегда рекомендуется. Diagnostic Services помогут.

+0

Я получил экспорт работать, но каждый раз, когда я пытаюсь разрешить зависимость в моем коде с Ioc.Get я получил «IoC не инициализирован» ... Я использую в своем коде много IoC.Get . В моем коде я переопределяю методы GetInstance, BuildUp, GetAllInstances согласно http://www.cshandler.com/2013/03/basics-of-caliburn-micro-with-simple.html – advapi

+0

@advapi не стесняйтесь публиковать сообщения эта проблема возникает как еще один вопрос с вашим кодом, и мы будем более чем рады помочь ... – qujck

2

Если вы явно зарегистрируете как ленивую, так и нормальную версию регистрации, ваш граф объектов будет по-прежнему полностью поддающимся проверке. Посмотрите на эту регистрацию:

container.Register<ITaggable, CorporateActionViewModel>(); 
container.Register<Lazy<ITaggable>>(
    () => new Lazy<ITaggable>(container.GetInstance<ITaggable>)); 

container.Verify(); 

Проверка будет идти через все явные регистрации и пытается создать экземпляр для каждого из регистраций. Это означает, что он создаст экземпляр Lazy<ITaggable>. Конечно, возможность создания Lazy<ITaggable> не означает, что можно создать CorporateActionViewModel, но Simple Injector также проверит регистрацию ITaggable. Эти два вместе убедитесь, что ваша полная конфигурация DI проверена.

Следующая конфигурация однако даст вам ложное чувство безопасности:

container.Register<Lazy<ITaggable>>(
    () => new Lazy<ITaggable>(container.GetInstance<CorporateActionViewModel>)); 

container.Verify(); 

Здесь Lazy<ITaggable> регистрации устройства используется GetInstance<CorporateActionViewModel> как метод фабрики, но CorporateActionViewModel не зарегистрирована в явном виде. Во время проверки Simple Injector создаст Lazy<ITaggable>, который, очевидно, преуспеет, но он не будет автоматически вызывать для вас свойство Lazy<T>.Value (что преднамеренно, потому что может быть причина, по которой вы отложили создание графа объектов).

Но, пожалуйста, пересмотреть свою стратегию инъекции ленивых на всей базе кода. Это плохая идея и плохая практика. Пожалуйста, прочитайте this и this для получения дополнительной информации.

2

И в ответ на ваш второй вопрос. (Вы знаете, что вы могли бы изменить свой вопрос. Это держит вещи понятные)

Я думаю, что я могу реорганизовать его

ContainerInstance.RegisterSingle<ISharedModuleObject>(
    new SharedModuleObject { DataLavorativa = DateTime.Today, 
    DataLavorativaPrecedente = DateTime.Today }); 

Но это нормально?

Я так не считаю. Вы называете это фабрикой, поэтому RegisterSingle(), который регистрирует экземпляр singleton, не в порядке.

Я думаю, что ваша реализация должна быть:

public class SharedModuleObject : ISharedModuleObject 
{ 
    public SharedModuleObject() 
    { 
     this.DataLavorativa = DateTime.Now; 
     this.DataLavorativaPrecedente = DateTime.Now; 
    } 

    public DateTime DataLavorativaPrecedente { get; set; } 
    public DateTime DataLavorativa { get; set; } 
} 

и зарегистрировать это нравится:

ContainerInstance.Register<ISharedModuleObject, SharedModuleObject>(); 

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

Edit:

Ваш комментарий Я понимаю, что вы на самом деле нужен синглтон.В этом случае ваш код был в порядке, но это, кажется, немного чище мне:

ContainerInstance.RegisterSingle<ISharedModuleObject, SharedModuleObject>(); 
+0

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

+0

Если вам нужен синглтон, вы можете изменить свой код на: 'ContainerInstance.RegisterSingle' или использовать то, что у вас уже было. он назвал фабрику взорвал меня в неправильном направлении –

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