Unity behavior for registering the same type twice and resolving only the singleton
.net, c#, dependency-injection, inversion-of-control, unity-container
Solution
Let's break it down:
_container.RegisterType<Music>(new InjectionConstructor(
new Album("Non-singleton", "Non-singleton")));
This registers with the container the type `Music` with no name (null or default) and tells Unity to use the constructor that accepts a type `Album`. Also to always pass the instance created by `new Album("Non-singleton", "Non-singleton")` as the value to the `Music(Album album)` constructor. So every `Music` instance will have the same Album injected into it.
_container.RegisterType<Music>(new ContainerControlledLifetimeManager());
This performs a registration based on the type `Music` with no name (null or default). Because, there are no InjectionMembers specified the only change to the existing registration is to add a lifetime manager. The existing registration is updated because the BuildKey (Type: Music, Name: null) is the same for both RegisterType calls.
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);
In the above areEqual is true, so a single instance is being returned.
Is there a way to Resolve only the singleton type for two registered objects in the same container w/out specifying a Name attribute?
Types are registered by Type and Name so the only way to have multiple registrations for the same type is to use a name:
// Named registration
unityContainer.RegisterType<Music>("NonSingleton Name",
new InjectionConstructor(new Album("Non-singleton", "Non-singleton")));
// Default (null) registration
unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager());
Now if you wanted to override the first registration you could do that by specifying a new InjectionConstructor. This would clear the build plan and set the constructor selection policy.
unityContainer.RegisterType<Music>(new InjectionConstructor(
new Album("Non-singleton", "Non-singleton")));
unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(new Album("singleton", "singleton")));
As a side note, you would usually not hard code the dependency (in this case Album) inside of the register type call unless it was truly a constant value. Even then you might want to register the constant instance as a singleton and let the container resolve it for you.
An interesting question is how would you reset the constructor selection policy after the first RegisterType call so that Unity would use its default constructor selection policy. You could do this with a custom InjectionMember that clears the constructor selection policy:
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));
}
}
Problem
I've been playing around with Unity to understand it a bit more, and came across the following scenario. If I was to register the same type twice, but with one being a singleton, how can I call `Resolve` so that only the singleton is returned? I understand that this can be accomplished using a unique `Name`, but am wondering if this can be done without. For example: ``` _container.RegisterType<Music>(new InjectionConstructor(new Album("Non-singleton", "Non-singleton"))); _container.RegisterType<Music>(new ContainerControlledLifetimeManager()); ``` and calling ``` var music = Factory.Resolve<Music>(); ``` returns the 'Non-singleton' object. At first, I thought it was based on registration order, but switching that around I still receive the 'Non-singleton' instance. Is there a reason for this? Is there a way to `Resolve` only the singleton type for two registered objects in the same container w/out specifying a `Name` attribute?