2009-09-08 3 views
36

как зарегистрировать два различных интерфейса в Unity с тем же экземпляром ... В настоящее время я используюUnity Регистрация двух интерфейсов как один одноплодной

 _container.RegisterType<EventService, EventService>(new ContainerControlledLifetimeManager()); 
     _container.RegisterInstance<IEventService>(_container.Resolve<EventService>()); 
     _container.RegisterInstance<IEventServiceInformation>(_container.Resolve<EventService>()); 

, который работает, но не выглядит красиво ..

Итак, я думаю, вы поняли эту идею. EventService реализует два интерфейса, я хочу ссылку на один и тот же объект, если я разрешу интерфейсы.

Крис

+0

OK, Если это путь, я просто держу его. Было просто интересно, если был более элегантный способ, но он работает, и в этом суть. Мне очень нравится Unity до сих пор ... довольно приятно в сочетании с PRISM –

+0

Посмотрите на ответ Свена ... у него много заслуг. Ознакомьтесь с комментариями @Chris Tavares о моем ответе на некоторые подробности. Проверьте это, и если вам это нравится, я бы призвал вас отметить это как ответ для других людей. –

ответ

13

Редактировать

После некоторой обратной связи в комментариях, я решил, что ответ Свена гораздо выше ответ. Спасибо Крису Таваресу за указание технических достоинств.


Это практически единственный способ сделать это.

Вы можете изменить его немного (я ненавижу RegisterType с тем же типом для каждого родового параметра):

EventService es = _container.Resolve<EventService>(); 
_container.RegisterInstance<IEventService>(es); 
_container.RegisterInstance<IEventServiceInformation>(es); 

Если один или несколько из ваших детей IoC собирается запросить тип бетона EventService (надеюсь, не) вы должны добавить еще один RegisterInstance типа RegisterInstance<EventService>. Надеюсь, вам это не понадобится, и все зависимые объекты запрашивают IEventService, а не EventService.

Надеется, что это помогает, Андерсон

+5

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

+0

@Nigel Thorne: Как правило, это правда, но в этом случае OP имел услугу, которую он/она должен был зарегистрировать, много зависимостей. Я предложил Unity создать этот объект, чтобы эти зависимости были автоматически разрешены, чтобы экземпляр мог использоваться для обоих вызовов Register (ему/ей нужен тот же экземпляр, который был возвращен для любого интерфейса). Обычно это нежелательно, но на самом деле это единственный способ сделать это в этом случае (кроме создания экземпляра объекта вручную). –

+3

На самом деле это не так - используйте вместо этого ответ Свена Кунцлера. –

51

[Редактировать]

Решение для этого с помощью конфигурации XML можно найти here. На основании этого ответа я хотел бы предложить обтекаемый код только подход следующим образом:

_container.RegisterType<IEventService, EventService>(new ContainerControlledLifetimeManager()); 
_container.RegisterType<IEventServiceInformation, EventService>(new ContainerControlledLifetimeManager()); 
bool singleton = ReferenceEquals(_container.Resolve<IEventService>(), _container.Resolve<IEventServiceInformation>()); 

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

[Подлинный ответ]

Немного поздно ответ, но должен сделать трюк:

_container.RegisterType<EventService>(new ContainerControlledLifetimeManager()); 
_container.RegisterType<IEventService, EventService>(); 
_container.RegisterType<IEventServiceInformation, EventService>(); 

bool singleton = ReferenceEquals(_container.Resolve<IEventService>(), _container.Resolve<IEventServiceInformation>()); 
+0

Кто-нибудь знает, как это сделать через конфигурацию? – JML

+0

Я также хотел бы знать, как это сделать через конфигурацию. – lukebuehler

+6

Интересно, что (по крайней мере, здесь) кажется, что при установке одной из тех, у кого есть именованная регистрация, она не работает ... – Reddog

0

Одно решение, которое также может работать в названных случаях является использование шаблона адаптера для создания переходные адаптеры к интерфейсу, которые обтекают экземпляры singleton. Затем разрешенные экземпляры всегда будут направлены на экземпляр singleton, событие, если они разрешены с помощью ResolveAll. Это помогает при наличии кучи сервисов, реализующих общий интерфейс, такой как IStartable или что-то в этом роде.

public class EventServiceAdapter<T> : IEventService where T : IEventService 
{ 
    private readonly T _adapted; 
    EventServiceAdapter(T adapted) 
    { 
     _adapted = adapted; 
    } 
    public string SomeMethod() 
    { 
     return _adapted.SomeMethod(); 
    } 
} 

Затем зарегистрируйте адаптер интерфейса вокруг зарегистрированного одноэлементного типа.

_container 
    .RegisterType<EventService>(new ContainerControlledLifetimeManager()) 
    .RegisterType<IEventService, EventServiceAdapter<EventService>>("namedEventService"); 

Вы можете скрыть любую одноплодной за любое количество интерфейсов, а также работу с использованием как Решимость и ResolveAll.

4

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

InjectionFactory factory = new InjectionFactory(x => x.Resolve<SimulationService>()); 
this.Container.RegisterType<SimulationService>(new ContainerControlledLifetimeManager()); 
this.Container.RegisterType<IContentProvider>("SimulationContentProvider", factory); 
this.Container.RegisterType<ISimulationService>(factory); 

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

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