2009-09-08 10 views
36

Jak zarejestrować dwa różne interfejsy w jedności z tej samej instancji ... Obecnie używamUnity Rejestruj dwa interfejsy jako jeden Singleton

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

który działa, ale nie wyglądają ładnie ..

Myślę, że masz pomysł. EventService implementuje dwa interfejsy, chcę odwołać się do tego samego obiektu, jeśli rozwiążę interfejsy.

Chris

+0

OK, jeśli to jest droga, po prostu ją zatrzymam. Interesowało mnie tylko, czy istnieje bardziej elegancki sposób, ale działa, i na tym właśnie polega. Naprawdę lubię Unity do tej pory ... całkiem niezły w połączeniu z PRISM –

+0

Spójrz na odpowiedź Svena ... ma wiele zalet. Sprawdź komentarze do @Chris Tavares w mojej odpowiedzi na kilka szczegółów. Sprawdź to, a jeśli ci się spodoba, zachęcam cię do zaznaczenia tego jako odpowiedzi dla innych ludzi. –

Odpowiedz

13

Edit

Po pewnym sprzężeniem zwrotnym w komentarzach Zdecydowałem, że odpowiedź Svena jest znacznie lepsza odpowiedź. Podziękowania dla Chrisa Tavaresa za wskazanie zalet technicznych.


To jedyny sposób, aby to zrobić.

Można go modyfikować nieznacznie (nienawidzę RegisterType tego samego typu dla każdego parametru rodzajowego):

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

Jeżeli jedno lub więcej dzieci MKOl zamierza zażądać rodzaj betonu EventService (oby nie) dodać jeszcze jeden RegisterInstance typu RegisterInstance<EventService>. Mam nadzieję, że tego nie potrzebujesz, a wszystkie obiekty zależne wymagają raczej IEventService niż EventService.

Nadzieja to pomaga, Anderson

+5

To jest dobra praktyka z wtryskiem zależności, aby oddzielić czas okablowania od czasu rozwiązania w jak największym stopniu. To rozwiązanie ma tę wadę, że wymaga połączenia połączeń w celu "rozwiązania" z wywołaniami "rejestracji" –

+0

@Nigel Thorne: Ogólnie jest to prawdą, ale w tym przypadku OP miał usługę, którą musiał zarejestrować, wiele zależności. Zasugerowałem, aby Unity utworzyło ten obiekt, aby te zależności zostały automatycznie rozwiązane, aby instancja mogła zostać użyta do obu wywołań Register (potrzebna była ta sama instancja zwrócona dla każdego z interfejsów). Zwykle jest to niepożądane, ale tak naprawdę jedyny sposób, aby to zrobić w tym przypadku (poza instancją obiektu ręcznie). –

+3

To naprawdę nie jest droga - zamiast tego użyj odpowiedzi Svena Kunzlera poniżej. –

51

[Edytuj]

Rozwiązaniem dla tej konfiguracji poprzez XML można znaleźć here. Na podstawie tej odpowiedzi chciałbym zaproponować uproszczone podejście kodu tylko w następujący sposób:

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

ten sposób sama klasa EventService nie jest publikowany przez kontener. Ponieważ klasa powinna być uważana za szczegół implementacji, jest to preferowane podejście.

[odpowiedź Original]

Trochę późno odpowiedź, ale powinno wystarczyć:

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

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

czy ktoś wie jak to zrobić poprzez konfigurację? – JML

+0

Chciałbym również wiedzieć, jak to zrobić poprzez konfigurację. – lukebuehler

+6

Co ciekawe, (przynajmniej tutaj) wydaje się, że przy ustawianiu jednej z nich na nazwaną rejestrację nie działa ... – Reddog

0

Jedno rozwiązanie, które może również pracować dla nazwanych wystąpień jest wykorzystanie wzoru karty do tworzenia rzucać adaptery do interfejsu, który owija się wokół instancji singleton. Następnie rozwiązane instancje będą zawsze kierowane do instancji singleton, zdarzenia, jeśli zostaną rozstrzygnięte za pomocą opcji ResolveAll. Pomaga to w przypadku mnóstwa usług implementujących ogólny interfejs, taki jak IStartable lub coś takiego.

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

Następnie zarejestruj adapter interfejsu wokół zarejestrowanego typu singleton.

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

Następnie można ukryć singleton za dowolną liczbę interfejsów oraz pracę z wykorzystaniem zarówno Resolve i ResolveAll.

4

Podejście z adapterem wydawało się nieporęczne na tak prostą rzecz, więc spojrzałem trochę dalej. Aby obejść problem z nazwanymi instancjami, musisz zarejestrować typ i zarejestrować fabryki dla interfejsów.

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); 

W ten sposób nie ma potrzeby tworzenia instancji klasy betonu (przy rejestracji), co nie było możliwe w moim przypadku z powodu brakujących zależnościach.

Powiązane problemy