用于两次注册相同类型并仅解析单例的Unity行为

d.m*_*ada 7 .net c# dependency-injection inversion-of-control unity-container

我一直在玩Unity以了解它,并遇到了以下情况.如果我要两次注册相同类型,但是一个是单例,我怎么调用Resolve才能返回单例?我知道这可以使用一个独特的Name,但我想知道如果没有这个可以完成.

例如:

_container.RegisterType<Music>(new InjectionConstructor(new Album("Non-singleton", "Non-singleton")));
_container.RegisterType<Music>(new ContainerControlledLifetimeManager());
Run Code Online (Sandbox Code Playgroud)

并打电话

var music = Factory.Resolve<Music>();
Run Code Online (Sandbox Code Playgroud)

返回'Non-singleton'对象.起初,我认为这是基于注册顺序,但切换我仍然收到'非单例'实例.

是否有一个原因?有没有办法Resolve只在同一容器中的两个注册对象的单例类型w/out指定Name属性?

Ran*_*ica 25

让我们分解一下:

_container.RegisterType<Music>(new InjectionConstructor(
    new Album("Non-singleton", "Non-singleton")));
Run Code Online (Sandbox Code Playgroud)

Music将向容器注册没有名称的类型(null或default),并告诉Unity使用接受类型的构造函数Album.也始终将new Album("Non-singleton", "Non-singleton")作为值创建的实例传递给Music(Album album)构造函数.所以每个Music实例都会注入相同的Album.

_container.RegisterType<Music>(new ContainerControlledLifetimeManager());
Run Code Online (Sandbox Code Playgroud)

这将根据Music没有名称的类型(null或default)执行注册.因为,没有指定InjectionMembers,对现有注册的唯一更改是添加生命周期管理器.现有注册已更新,因为两个RegisterType调用的BuildKey(类型:音乐,名称: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);
Run Code Online (Sandbox Code Playgroud)

在上面的areEqual是真的,所以返回一个实例.

有没有一种方法来解决在同一容器中两个注册的对象只有单型瓦特/输出指定名称的属性?

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

// Named registration
unityContainer.RegisterType<Music>("NonSingleton Name",
    new InjectionConstructor(new Album("Non-singleton", "Non-singleton")));

// Default (null) registration
unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager());
Run Code Online (Sandbox Code Playgroud)

现在,如果您想覆盖第一次注册,可以通过指定新的InjectionConstructor来实现.这将清除构建计划并设置构造函数选择策略.

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

unityContainer.RegisterType<Music>(new ContainerControlledLifetimeManager(),
    new InjectionConstructor(new Album("singleton", "singleton")));
Run Code Online (Sandbox Code Playgroud)

作为旁注,您通常不会在寄存器类型调用内部对依赖项(在本例中为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));
    }
}
Run Code Online (Sandbox Code Playgroud)