注册同一类型两次并仅解析单一实例的 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属性?

注册同一类型两次并仅解析单一实例的 Unity 行为

让我们分解一下:

_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));
    }
}