注册同一类型两次并仅解析单一实例的 Unity 行为
本文关键字:单一 实例 行为 Unity 两次 类型 注册 | 更新日期: 2023-09-27 18:27:56
我一直在玩Unity以更多地理解它,并遇到了以下情况。如果我要注册两次相同的类型,但其中一个是单例,我如何调用Resolve
以便只返回单例?我知道这可以使用独特的Name
来完成,但我想知道是否可以不这样做。
例如:
_container.RegisterType<Music>(new InjectionConstructor(new Album("Non-singleton", "Non-singleton")));
_container.RegisterType<Music>(new ContainerControlledLifetimeManager());
和呼叫
var music = Factory.Resolve<Music>();
返回"非单一实例"对象。起初,我以为它是基于注册顺序,但切换它,我仍然会收到"非单例"实例。
这有什么原因吗?有没有办法只Resolve
同一容器中两个注册对象的单一实例类型,而无需指定Name
属性?
让我们分解一下:
_container.RegisterType<Music>(new InjectionConstructor(
new Album("Non-singleton", "Non-singleton")));
这会向容器注册没有名称(null 或默认值(的类型Music
,并告诉 Unity 使用接受类型Album
的构造函数。 此外,始终将 new Album("Non-singleton", "Non-singleton")
创建的实例作为值传递给 Music(Album album)
构造函数。 因此,每个Music
实例都会注入相同的相册。
_container.RegisterType<Music>(new ContainerControlledLifetimeManager());
这将基于没有名称(null 或默认值(的类型Music
执行注册。因为,没有指定注入成员,所以对现有注册的唯一更改是添加生存期管理器。 现有注册已更新,因为两个 RegisterType 调用的生成密钥(类型:音乐,名称:null(相同。
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);
在上面是等于是真的,所以返回一个实例。
类型有没有办法在不指定 Name 属性的情况下仅解析同一容器中两个已注册对象的单一实例类型?
按类型和名称注册,因此对同一类型进行多个注册的唯一方法是使用名称:
// Named registration
unityContainer.RegisterType<Music>("NonSingleton Name",
new InjectionConstructor(new Album("Non-singleton", "Non-singleton")));
// Default (null) registration
unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager());
现在,如果你想覆盖第一个注册,你可以通过指定一个新的 InjectionConstructor 来实现。 这将清除构建计划并设置构造函数选择策略。
unityContainer.RegisterType<Music>(new InjectionConstructor(
new Album("Non-singleton", "Non-singleton")));
unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(new Album("singleton", "singleton")));
作为旁注,您通常不会在寄存器类型调用中对依赖项(在本例中为 Album(进行硬编码,除非它确实是一个常量值。 即便如此,您可能希望将常量实例注册为单一实例,并让容器为您解析它。
一个有趣的问题是,如何在第一次 RegisterType 调用后重置构造函数选择策略,以便 Unity 使用其默认构造函数选择策略。 您可以使用清除构造函数选择策略的自定义 InjectionMember 来执行此操作:
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));
}
}