Ich verwende Register Unity vereinbarungs Mechanismus in dem folgende Szenario:Warum wird ein Typ zweimal registriert, wenn der Lifetime Manager angegeben wird?
unityContainer.RegisterTypes(
new[] { typeof(Implementation) },
WithMappings.FromAllInterfaces,
WithName.Default,
WithLifetime.ContainerControlled);
Danach:
public interface IInterface { }
public class Implementation : IInterface { }
Bei Implementation
Klasse und ihre Schnittstelle I RegisterTypes
auf folgende Weise renne Anruf, unitContainer
enthält drei Registrierungen:
IUnityContainer
->IUnityContainer
(ok)IInterface
->Implementation
(ok)Implementation
->Implementation
(???)
Wenn ich den Anruf wie folgt ändern:
unityContainer.RegisterTypes(
new[] { typeof(Implementation) },
WithMappings.FromAllInterfaces,
WithName.Default);
Der Container enthält nur zwei Registrierungen:
IUnityContainer
->IUnityContainer
(ok)IInterface
->Implementation
(ok)
(dies das gewünschte Verhalten).
Nachdem ich in Unity's source code spähen, habe ich bemerkt, dass es einige Missverständnisse darüber gibt, wie IUnityContainer.RegisterType
funktionieren sollte.
Die RegisterTypes
Methode funktioniert wie folgt (die Kommentare anzuzeigen, was sind die Werte in den Szenarien oben dargestellt):
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); // !
}
}
Da fromTypes
nicht leer ist, fügt der RegisterTypeMappings
eine Typzuordnung: IInterface
->Implementation
(richtig).
im Falle Wenn dann lifetimeManager
nicht null ist, versucht der Code die Lebensdauer Manager mit dem folgenden Aufruf zu ändern:
container.RegisterType(type, name, lifetimeManager, injectionMembers);
Der Name dieser Funktion völlig irreführend, weil the documentation eindeutig fest, dass:
RegisterType ein LifetimeManager für den angegebenen Typ und Namen mit dem Container. Für diesen Typ wird keine Typzuordnung durchgeführt.
Leider ist nicht nur der Name irreführend, aber die Dokumentation ist falsch. Wenn ich diesen Code debugge, habe ich festgestellt, dass, wenn es kein Mapping von type
(Implementation
in den oben dargestellten Szenarien) gibt, es hinzugefügt wird (wie type
->type
) und deshalb enden wir mit drei Registrierungen im ersten Szenario .
Ich habe Unity Quellen heruntergeladen, das Problem zu beheben, aber ich habe den folgenden Unit-Test gefunden:
[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);
// ...
- die fast genau mein Fall ist, und führe zu meiner Frage:
Warum wird das erwartet? Ist es ein konzeptioneller Fehler, ein Komponententest, der erstellt wurde, um dem vorhandenen Verhalten zu entsprechen, aber nicht unbedingt korrekt, oder fehlt mir etwas Wichtiges?
Ich verwende Unity v4.0.30319.
Der Teil über die Notwendigkeit, mehrere Instanzen eines Standard Lifetime Managers zu haben, wenn mehrere Interfaces vorhanden sind, scheint ein starkes Argument zu sein und der einzige konkrete Grund dafür. Vielen Dank! – BartoszKP