Unity behavior for registering the same type twice and resolving only singleton

I played with Unity to understand it a little more, and came across the following scenario. If I registered the same type twice, but one of them was single, how can I call Resolve so that only one singleton returns? I understand that this can be done using a unique Name , but I wonder if it can be done without it.

For instance:

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

and challenge

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

returns a non-singleton object. At first, I thought it was based on registration order, but by switching it, I still get an instance of "Non-singleton".

Is there a reason for this? Is there a way to Resolve use only a singleton type for two registered objects in the same container without specifying the Name attribute?

+6
source share
1 answer

Let me break it:

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

This registers a container of type Music with no name (null or default) and tells Unity to use a constructor that takes type Album . Also always pass the instance created by new Album("Non-singleton", "Non-singleton") as the value for the Music(Album album) constructor. Thus, each instance of Music will have the same album that was introduced into it.

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

Performs registration based on type Music with no name (null or default). Because, there are no InjectionMembers pointers, the only change to the existing registration is to add a lifespan manager. The current 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 example, isqual is true, so one instance is returned.

Is there a way to allow only a singleton type for two registered objects in the same container without specifying the Name attribute?

Types are registered by type and name, so the only way to have multiple registrations for the same type is to use the 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 want to redefine the first registration, you can do this by specifying a new InjectionConstructor. This will clear the build plan and establish a 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 will usually not hardcode the dependency (in this case, Album) inside a register type call if it was not a really constant value. Even then, you might want to register a permanent instance as a singleton, and let the container allow it for you.

An interesting question: how would you reset the constructor selection policy after the first call to RegisterType so that Unity uses the default constructor selection policy. You can do this with a special 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)); } } 
+21
source

Source: https://habr.com/ru/post/951910/


All Articles