2011-01-17 18 views
6

Widzę dziwne zachowanie w kontenerze Unity, gdy pracuję z dwoma interfejsami, które rejestrują się w tym samym dekoratorze. Przykład kodu będzie wyraźniejszy.Unity: Rejestracja tego samego typu dla dwóch interfejsów

Mam następujące klasy Hierarchia:

public interface IBaseInterface 
    { 

    } 

    public interface IInterface1: IBaseInterface 
    { 

    } 
    public interface IInterface2: IBaseInterface 
    { 

    } 
    public class Interface1Impl : IInterface1 
    { 
    } 
    public class Interface2Impl : IInterface2 
    { 
    } 

    public class BaseInterfaceDecorator: IInterface1,IInterface2 
    { 
     private readonly IBaseInterface baseInterface; 

     public BaseInterfaceDecorator(IBaseInterface baseInterface) 
     { 
      this.baseInterface = baseInterface; 
     } 
    } 

    public class MyClass 
    { 
     private readonly IInterface1 interface1; 

     public MyClass(IInterface1 interface1) 
     { 
      this.interface1 = interface1; 
     }    
    } 

I to jest kod rejestracyjny:

var container = new UnityContainer();   
     container.RegisterType<IInterface1, BaseInterfaceDecorator>(
      new InjectionConstructor(
       new ResolvedParameter<Interface1Impl>())); 

     container.RegisterType<IInterface2, BaseInterfaceDecorator>(
      new InjectionConstructor(
       new ResolvedParameter<Interface2Impl>())); 


     var dependency = container.Resolve<MyClass>(); 

Podczas rozwiązywania MojaKlasa Dostaję BaseInterfaceDecorator z Interface2Impl zamiast Interface1Impl. Wydaje mi się to dziwne. Możesz wytłumaczyć?

Odpowiedz

9

Wygląda na to, że ostatnia instrukcja wstrzykiwania dla danego typu "do" wygrywa. Jeśli pobierzesz kopię Reflector i przyjrzymy się implementacji UnityContainer.RegisterType (Typ, Typ, ciąg, LifetimeManager, InjectionMember []), zobaczysz dlaczego.

IMO, to zachowanie jest błędem. Przynajmniej InjectedMembers.ConfigureInjectionFor (Type, string, InjectionMember []) powinien rzucić wyjątek zamiast cichej wymiany poprzedniej konfiguracji wtrysku. Jednak naprawdę powinien wspierać to, co próbujesz.

+0

W przypadku, gdy nie jest jasne dla czytelników; Wewnętrznie Unity buforuje klucz budowania typu "do" (np. "TTo" w ogólnych sygnaturach). Przy następnym rozwiązaniu dowolnego typu "TFrom" klucz kompilacji dla "TTo" jest używany do wykonania kompilacji. Ten klucz budowania jest również powiązany z menedżerem na całe życie i dlatego Unity wydaje się używać pierwszego używanego menedżera na całe życie (w Build Up) dla wszystkich zastępczych rozstrzygnięć dla TTo (niezależnie od tożsamości TFrom). To jest błąd z Unity's Buduj klucze. Rozwiązaniem jest użycie nazwanych rejestracji, które pokonują punkt w tworzeniu tożsamości kowariancyjnych. –

2

Nie wiem, czy to pomaga. Najprawdopodobniej już za późno. Jest to jednak możliwe do osiągnięcia, jeśli używasz nazwanej rejestracji, tzn. Rejestrujesz każdy typ, który ma zostać rozwiązany pod inną nazwą.

Na przykład:

Container.RegisterType<IInterface1, BaseInterfaceDecorator>("interface1"); 
Container.RegisterType<IInterface2, BaseInterfaceDecorator>("interface2"); 
+0

Jest to poprawne obejście, ale pokonuje cel przy użyciu typów kowariantnych w rejestracji. Unity sprawia, że ​​założenie, że wszystkie rozwiązują dla "TTo" odnosi się do tej samej konfiguracji/instrukcji tworzenia instancji TTo. W ten sposób pojawią się problemy z parametrami wtrysku i zarządzania wieczystym, w których tożsamość TFrom powinna powodować różne zachowania (różne wtryskiwanie, inny menedżer życia itd.) –

Powiązane problemy