che sto usando di Unity Registrati per convenzione meccanismo nel seguente scenario:Perché un tipo è registrato due volte quando è specificato il gestore della durata?
public interface IInterface { }
public class Implementation : IInterface { }
Dato Implementation
classe e la sua interfaccia sto correndo RegisterTypes
nel seguente modo:
unityContainer.RegisterTypes(
new[] { typeof(Implementation) },
WithMappings.FromAllInterfaces,
WithName.Default,
WithLifetime.ContainerControlled);
Dopo questo chiamare, unitContainer
contiene tre registrazioni:
IUnityContainer
->IUnityContainer
(ok)IInterface
->Implementation
(ok)Implementation
->Implementation
(???)
Quando cambio la chiamata come segue:
unityContainer.RegisterTypes(
new[] { typeof(Implementation) },
WithMappings.FromAllInterfaces,
WithName.Default);
Il contenitore contiene solo due registrazioni:
IUnityContainer
->IUnityContainer
(ok)IInterface
->Implementation
(ok)
(questo è il comportamento desiderato).
Dopo aver sbirciato in Unity's source code, ho notato che c'è qualche incomprensione su come IUnityContainer.RegisterType
dovrebbe funzionare.
Il metodo RegisterTypes
funziona nel modo seguente (i commenti che indicano quali sono i valori negli scenari presentati in precedenza):
foreach (var type in types)
{
var fromTypes = getFromTypes(type); // { IInterface }
var name = getName(type); // null
var lifetimeManager = getLifetimeManager(type); // null or ContainerControlled
var injectionMembers = getInjectionMembers(type).ToArray(); // null
RegisterTypeMappings(container, overwriteExistingMappings, type, name, fromTypes, mappings);
if (lifetimeManager != null || injectionMembers.Length > 0)
{
container.RegisterType(type, name, lifetimeManager, injectionMembers); // !
}
}
Perché fromTypes
non è vuoto, il RegisterTypeMappings
aggiunge un tipo di mappatura: IInterface
->Implementation
(corretta).
Poi, nel caso in cui lifetimeManager
non è nullo, il codice tenta di cambiare il manager vita con la seguente chiamata:
container.RegisterType(type, name, lifetimeManager, injectionMembers);
nome di questa funzione è completamente fuorviante, perché the documentation afferma chiaramente che:
Register Digitare un LifetimeManager per il tipo e il nome specificati con il contenitore. Nessun tipo di mappatura viene eseguita per questo tipo.
Sfortunatamente, non solo il nome è fuorviante, ma la documentazione è sbagliata. Quando ho eseguito il debug di questo codice, ho notato che quando non c'è alcuna mappatura da type
(Implementation
negli scenari presentati sopra), viene aggiunto (come type
->type
) ed è per questo che ci ritroviamo con tre registrazioni nel primo scenario .
Ho scaricato fonti di Unity per risolvere il problema, ma ho trovato il seguente test unità:
[TestMethod]
public void RegistersMappingAndImplementationTypeWithLifetimeAndMixedInjectionMembers()
{
var container = new UnityContainer();
container.RegisterTypes(new[] { typeof(MockLogger) }, getName: t => "name", getFromTypes: t => t.GetTypeInfo().ImplementedInterfaces, getLifetimeManager: t => new ContainerControlledLifetimeManager());
var registrations = container.Registrations.Where(r => r.MappedToType == typeof(MockLogger)).ToArray();
Assert.AreEqual(2, registrations.Length);
// ...
- che è quasi esattamente il mio caso, e conduce alla mia domanda:
Perché è previsto? È un errore concettuale, un test unitario creato per corrispondere al comportamento esistente ma non necessariamente corretto, o mi manca qualcosa di importante?
Sto utilizzando Unity v4.0.30319.
La parte relativa all'impossibilità di disporre di più istanze di un gestore lifetime predefinito quando ci sono più interfacce sembra essere un argomento valido e l'unica ragione concreta finora. Grazie! – BartoszKP