2014-09-24 29 views
5

Ho giocato con il contenitore Unity e ho notato uno strano comportamento. Ho una classe, che implementa più di un'interfaccia. Voglio che questa classe sia usata in posti diversi attraverso un'applicazione con vite diverse. Quindi ho mappato IFooDerived1 a Foo come Singleton e IFooDerived2 a Foo come Transient. Ma qualsiasi registrazione di Foo corrompe precedenti registrazioni di Foo.Unity RegisterType con LifetimeManager comportamento strano

Esempio:

interface IFoo { } 
    interface IFooDerived1 { } 
    interface IFooDerived2 { } 
    class Foo : IFoo, IFooDerived1, IFooDerived2 { } 

    static void Main(string[] args) 
    { 
     var container = new UnityContainer(); 

     container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager()); 
     container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager()); 
     container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager()); 

     foreach(var r in container.Registrations) 
     { 
      Console.WriteLine("{0} -> {1} : {2}", r.RegisteredType.Name, r.MappedToType.Name, r.LifetimeManagerType.Name); 
     } 
    } 

uscita:

IFoo -> Foo : TransientLifetimeManager 
    IFooDerived1 -> Foo : TransientLifetimeManager 
    IFooDerived2 -> Foo : TransientLifetimeManager 

È questo il comportamento corretto? Qualcuno può dare qualche spiegazione logica? Posso facilmente usare un altro approccio, voglio solo capire perché questo accada. Grazie.

+0

Oltre a questo preoccupante comportamento di Unity, potresti anche voler dare un'occhiata al tuo progetto, perché penso che dovresti estrarre il comportamento che "IFooDerived2" ti dà in un'implementazione diversa. Quella nuova implementazione 'FooDerived2' può dipendere da' IFoo'. – Steven

+0

Sì, hai ragione, il design non è molto buono. Ho già rielaborato il codice "reale". – boades

+0

Ma sono d'accordo con te, questo è un comportamento 'interessante'. – Steven

risposta

1

Se si modifica la registrazione al seguente:

container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager()); 
container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager()); 
container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager()); 

si otterrà il seguente risultato:

IFoo -> Foo : ExternallyControlledLifetimeManager 
    IFooDerived1 -> Foo : ExternallyControlledLifetimeManager 
    IFooDerived2 -> Foo : ExternallyControlledLifetimeManager 

WAT? Indipendentemente dall'astrazione che recuperi, otterrai sempre la stessa istanza. Quindi semplicemente cambiando l'ordine delle registrazioni si ottiene un comportamento completamente diverso dello stile di vita.

btw, il ExternallyControlledLifetimeManager è spaventoso come cazzo, perché utilizza uno weak reference to the object e potrebbe ricreare dopo l'applicazione non mantiene più un riferimento ad esso. Non dovresti quasi mai usare questo stile di vita.

Sto provando a capirlo, ma sembra che in Unity, quando si effettua una registrazione, si sta effettivamente registrando l'implementazione con un certo stile di vita e l'astrazione fornita si limita a mappare quella registrazione. Quindi, se si definisce un'API alternativa per l'Unità, l'iscrizione sarebbe diventa qualcosa di simile:

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); 
MapToEntry(from: typeof(IFoo), to: typeof(Foo)); 

Quindi, con questa API 'alternativa', diventa più chiaro che il seguente sta accadendo:

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); 
MapToEntry(from: typeof(IFoo), to: typeof(Foo)); 
MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); 
MapToEntry(from: typeof(IFooDerived1), to: typeof(Foo)); 
MakeEntry(typeof(Foo), new TransientLifetimeManager()); 
MapToEntry(from: typeof(IFooDerived2), to: typeof(Foo)); 

Il che significa che ci sono tre voci per lo stesso Foo e apparentemente Unity accetta semplicemente questo in silenzio e l'ultima chiamata vince. Non odi questo comportamento implicito?

È possibile passare a una libreria diversa?

+0

Analisi interessante, ma in realtà non risponde alla domanda ... –

+0

@ThomasLevesque I sapere :-) – Steven

+0

No.Trovo questo comportamento molto utile. –