6

Ho giocato con Unity per capirlo un po 'di più e ho trovato il seguente scenario. Se dovessi registrare lo stesso tipo due volte, ma con uno che è un singleton, come posso chiamare Resolve in modo che venga restituito solo il singleton? Capisco che questo può essere realizzato utilizzando un unico Name, ma mi chiedo se questo può essere fatto senza.Comportamento di unità per registrare due volte lo stesso tipo e risolvere solo il singleton

Ad esempio:

_container.RegisterType<Music>(new InjectionConstructor(new Album("Non-singleton", "Non-singleton"))); 
_container.RegisterType<Music>(new ContainerControlledLifetimeManager()); 

e chiamando

var music = Factory.Resolve<Music>(); 

restituisce l'oggetto 'non-Singleton'. All'inizio, pensavo che fosse basato sull'ordine di registrazione, ma passando a quel punto ricevo ancora l'istanza 'Non-singleton'.

C'è una ragione per questo? C'è un modo per Resolve solo il tipo singleton per due oggetti registrati nello stesso contenitore senza specificare un attributo Name?

risposta

21

Diamo scomposizione:

_container.RegisterType<Music>(new InjectionConstructor(
    new Album("Non-singleton", "Non-singleton"))); 

Ciò registra con il contenitore del tipo Music senza nome (default nullo o) e racconta l'Unità di utilizzare il costruttore che accetta un tipo Album. Inoltre, per passare sempre l'istanza creata da new Album("Non-singleton", "Non-singleton") come valore per il costruttore Music(Album album). Pertanto, ad ogni istanza di Music verrà iniettato lo stesso album.

_container.RegisterType<Music>(new ContainerControlledLifetimeManager()); 

Questo esegue una registrazione in base al tipo Music senza nome (null o di default). Poiché non sono stati specificati InjectionMembers, l'unica modifica alla registrazione esistente è l'aggiunta di un gestore della durata. La registrazione esistente viene aggiornata perché il BuildKey (Tipo: Musica, Nome: null) è lo stesso per entrambe le chiamate RegisterType.

unityContainer.RegisterType<Music>(new InjectionConstructor(new Album("Non-singleton", "Non-singleton"))); 

unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager()); 

var music = unityContainer.Resolve<Music>(); 
var music2 = unityContainer.Resolve<Music>(); 

bool areEqual = ReferenceEquals(music, music2); 

Nel caso in cui areEqual è true, viene restituita una singola istanza.

Esiste un modo per risolvere solo il tipo di singleton per due oggetti registrati nello stesso contenitore senza specificare un attributo Nome?

Tipi sono registrati per tipo e nome quindi l'unico modo per avere registrazioni multiple per lo stesso tipo è quello di utilizzare un nome:

Ora, se si voleva sostituire la prima registrazione che si possa fare specificando un nuovo InjectionConstructor. Ciò cancellerebbe il piano di build e imposterebbe la politica di selezione del costruttore.

unityContainer.RegisterType<Music>(new InjectionConstructor(
    new Album("Non-singleton", "Non-singleton"))); 

unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager(), 
    new InjectionConstructor(new Album("singleton", "singleton"))); 

Come nota a margine, si farebbe di solito non codificare la dipendenza (in questo caso album) all'interno del tipo di registro chiamate a meno che non era veramente un valore costante. Anche in questo caso potresti voler registrare l'istanza costante come un singleton e lasciare che sia il contenitore a risolverlo per te.

Una domanda interessante è come si ripristinerebbe la politica di selezione del costruttore dopo la prima chiamata RegisterType in modo che Unity utilizzi la sua politica di selezione costruttore predefinita. È possibile eseguire questa operazione con un InjectionMember personalizzato che cancella la politica di selezione del costruttore:

unityContainer.RegisterType<Music>(new InjectionConstructor(
    new Album("Non-singleton", "Non-singleton"))); 

unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager(), 
    new ClearInjectionConstructor()); 

public class ClearInjectionConstructor : InjectionMember 
{ 
    public override void AddPolicies(Type serviceType, 
     Type implementationType, 
     string name, 
     Microsoft.Practices.ObjectBuilder2.IPolicyList policies) 
    { 
     policies.Clear<IConstructorSelectorPolicy>(
      new NamedTypeBuildKey(implementationType, name)); 
    } 
} 
Problemi correlati