2010-01-01 2 views
2

Я хочу использовать Unity разрешить IService двух различных реализаций, чтобы сделать использование класса-оболочки, эквивалент:Разрешающая классы-оболочки в C# с контейнером Unity IoC

IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher); 

Где и DispatcherService и RealService реализации интерфейс IService.

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

public interface IService 
{ 
    IAsyncResult StartSomeOperation(); 
    event EventHandler<EventArgs> SomeOperationCompleted; 
} 

У меня есть реализации для всех этих услуг. Я хочу, чтобы эта библиотека оставалась свободной от зависимостей от WPF и IoC-контейнеров, но была готова для наилучшего использования в случаях, когда используются контейнеры IoC и, возможно, WPF.

У меня есть WPF Ui с использованием контейнера Unity IoC. Наиболее распространенный повторяющийся код связан с обработанными обработчиками - их нужно перенаправить обратно в поток пользовательского интерфейса с помощью Диспетчера. Так что я думаю о обертке, как это:

using System; 
using System.Windows.Threading; 

public class DispatcherService : IService 
{ 
    private Dispatcher dispatcher; 
    private IService wrappedService; 

    public DispatcherService(IService wrappedService, Dispatcher dispatcher) 
    { 
     this.wrappedService = wrappedService; 
     this.wrappedService.SomeOperationCompleted += this.OnWrappedOperationCompleted; 
     this.dispatcher = dispatcher; 
    } 

    public IAsyncResult StartSomeOperation() 
    { 
     return this.wrappedService.StartSomeOperation(); 
    } 

    public event EventHandler<EventArgs> SomeOperationCompleted; 

    private void OnWrappedOperationCompleted(object sender, EventArgs e) 
    { 
     if (this.SomeOperationCompleted != null) 
     { 
      Action completedSynch =() => this.SomeOperationCompleted(sender, e); 
      this.dispatcher.Invoke(completedSynch); 
     } 
    } 
} 

Я новое это с кодом, как

IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher); 

Но единству не нравится тот факт, что я сочиняет две различных реализации Интерфейс IService. Этот код не страшно:

UnityContainer container = new UnityContainer(); 
    container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher); 
    container.RegisterType<IService, RealService>(); 
    container.RegisterType<IService, DispatcherService>(); 

    IService created = container.Resolve<IService>(); 

И если я зарегистрировать свои услуги в другом порядке, то первая регистрация перезаписывается, и я просто получить RealService.

Есть ли способ обойти это с единством? Или это было сделано с АОП Unity? И если да, то работает ли это в Silverlight? Это можно сделать без использования Unity в исходной библиотеке вообще.

я могу работать вокруг с «маркером» интерфейса подкласса, т.е.

public interface IServiceWithDispatcher : IService 
{ 

} 

... 

UnityContainer container = new UnityContainer(); 
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher); 

container.RegisterType<IService, RealService>(); 
container.RegisterType<IServiceWithDispatcher, DispatcherService>(); 

Но я не думаю, что это хорошая идея, пустой интерфейс некрасиво и это не очень хорошо масштабируется ,

Какой способ разрешить это дерево объектов?


Update:

В соответствии с Dzmitry Huba и ответ дал, вот некоторые примеры кода:

Добавить ссылку на Microsoft.Practices.Unity.StaticFactory

Простой рабочий код:

UnityContainer container = new UnityContainer(); 

    container.AddNewExtension<StaticFactoryExtension>() 
     .Configure<IStaticFactoryConfiguration>() 
     .RegisterFactory<IService>(cont => 
       new DispatcherService(new RealService(), Application.Current.Dispatcher)); 

    IService created = container.Resolve<IService>(); 

Более полный рабочий код, который лучше подходит для p otential зависимости реальный сервис, как контейнер IoC должен:

UnityContainer container = new UnityContainer(); 
    container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher); 
    container.RegisterType<IService, RealService>("Real"); 

    container.AddNewExtension<StaticFactoryExtension>() 
     .Configure<IStaticFactoryConfiguration>() 
     .RegisterFactory<IService>(cont => 
       new DispatcherService(
         cont.Resolve<IService>("Real"), 
         cont.Resolve<Dispatcher>())); 

    IService created = container.Resolve<IService>() 

Кроме того, принимая во внимание, что регистрация завода действительно многословным, и я буду делать больше, чем один из них, я сделал метод расширения:

public static class ContainerExtensions 
{ 
    public static void RegisterFactory<T>(this IUnityContainer container, FactoryDelegate factoryDelegate) 
    { 
     container.AddNewExtension<StaticFactoryExtension>() 
      .Configure<IStaticFactoryConfiguration>() 
      .RegisterFactory<T>(factoryDelegate); 
    } 
} 

ответ

6

Вы можете использовать перегрузки RegisterType, которые принимают имена на основе строк. В этом случае вы сделаете что-то вроде:

container.RegisterType<IService, RealService>("real"); 
container.RegisterType<IService, DispatcherService>("dispatcher"); 

и сообщите также о своих зависимостях с именами.

[Dependency("real")] 

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

Однако, если вы хотите, чтобы ваш код был чистым из присутствия Unity (например, DependencyAttribute), и в большинстве случаев вы будете использовать только 1 реализацию в течение срока действия приложения (например, будет использоваться только DispatcherService), вы в основном принимаете решение о том, для переноса запрошенного IService с помощью DispatcherService или нет. В этом случае вы можете посмотреть Static Factory Extension for Unity. Фабричный делегат будет знать о конфигурации и на основе конфигурации будет либо обернуть IService с DispatcherService, либо просто вернуть реализацию IService, полученную из контейнера.

+0

Отлично, спасибо за статическое предложение завода. Вы должны добавить ссылку на Microsoft.Practices.Unity.StaticFactory. Я разместил несколько примеров кода. – Anthony

0

Я выяснил, что это необходимо сделать в контейнере Castle Windsor IoC. Просто зарегистрируйте классы в правильном порядке - сначала обертка, затем завернутый класс и правильная вещь.

например.

container.Kernel.AddComponent<IService, DispatcherService>(); 
container.Kernel.AddComponent<IService, RealService>(); 

Не только это много меньше возни, чем в единстве, он сохраняет один из ключевых преимуществ IoC - что если параметры к изменению конструктора DispatcherService, никакой другой код не нужно менять.

Будем надеяться, что будущая версия Unity начнет делать этот сценарий так же просто, как в Виндзоре.

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