7

我一直在玩 Unity 以进一步了解它,并遇到了以下场景。如果我要注册两次相同的类型,但其中一个是单例,我该如何调用Resolve以便只返回单例?我知道这可以使用 unique 来完成Name,但我想知道是否可以不这样做。

例如:

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

并打电话

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

返回“非单例”对象。起初,我以为它是基于注册顺序的,但切换它我仍然收到“非单例”实例。

是否有一个原因?有没有办法Resolve只为同一容器中的两个注册对象提供单例类型而不指定Name属性?

4

1 回答 1

25

让我们分解一下:

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

这会向容器注册Music没有名称(null 或默认)的类型,并告诉 Unity 使用接受 type 的构造函数Album。还要始终将由创建的实例new Album("Non-singleton", "Non-singleton")作为值传递给Music(Album album)构造函数。因此,每个Music实例都将注入相同的专辑。

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

Music这将根据没有名称(null 或默认)的类型执行注册。因为,没有指定 InjectionMembers,对现有注册的唯一更改是添加生命周期管理器。现有注册已更新,因为 BuildKey(类型:音乐,名称:null)对于两个 RegisterType 调用都是相同的。

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

在上面的 areEqual 为真,所以返回一个实例。

有没有办法只解决同一容器中两个已注册对象的单例类型,而无需指定名称属性?

类型是通过类型和名称注册的,因此对同一类型进行多次注册的唯一方法是使用一个名称:

// 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")));

作为旁注,您通常不会在寄存器类型调用中硬编码依赖项(在本例中为专辑),除非它确实是一个常量值。即使这样,您也可能希望将常量实例注册为单例并让容器为您解析它。

一个有趣的问题是如何在第一次 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));
    }
}
于 2013-08-17T15:58:25.123 回答