意外的Unity容器行为,具有相同类型的命名和未命名注册

时间:2017-03-02 13:36:57

标签: c# unity-container

我使用Unity版本2.1.505.2并在注册UnityContainer时使用默认注册和命名注册(使用ParameterOverride)查看相同的接口类型时出现意外行为。

如果我两次调用container.Resolve<T>() - 一次用于命名注册,一次用于默认注册 - 我得到相同的实例,而我期望基于两种不同的注册实例。

这是一个代码示例:

public interface ICage
{
    IAnimal Animal { get; }
}

public class Cage : ICage
{
    public IAnimal Animal { get; private set; }
    public Cage(IAnimal animal) { Animal = animal; }
}

public interface IAnimal
{
    string Species { get; }
}

public class Cat : IAnimal
{
    public string Species { get { return "Felis catus"; } }
}

public class Dog : IAnimal
{
    public string Species { get { return "Canis lupus"; } }
}

[TestClass]
public class UnityTest
{
    [TestMethod]
    public void MyTest()
    {
        var container = new UnityContainer();

        // Default registrations for IAnimal and ICage
        container.RegisterType<IAnimal, Cat>(new ContainerControlledLifetimeManager());
        container.RegisterType<ICage, Cage>(new ContainerControlledLifetimeManager());

        // Named registration "cage2" for ICage mapping to Cage with constructor parameter override
        container.RegisterType<ICage>(
            "cage2",
            new ContainerControlledLifetimeManager(),
            new InjectionFactory(c => c.Resolve<Cage>(new ParameterOverride("animal", new Dog()))));

        // Resolve ICage using the named registraion "cage2"
        var cage2 = container.Resolve<ICage>("cage2");
        Assert.AreEqual("Canis lupus", cage2.Animal.Species); // Assert succeeds

        // Resolve ICage using the default registration ???
        var cage = container.Resolve<ICage>();
        Assert.AreEqual("Felis catus", cage.Animal.Species); // Assert fails (Actual:<Canis lupus>)
    }
}

测试中的第二个断言失败,因为cage.Animal.Species返回"Canis lupus"

我错过了我的理解吗?如何进行设置以便对container.Resolve<ICage>("cage2")的调用返回与命名注册相对应的Cage实例,并且对container.Resolve<ICage>()的调用将返回与默认注册相对应的实例?

1 个答案:

答案 0 :(得分:1)

我花了2天时间解决你的问题,我已经知道了!

问题在于命名注册“cage2”。

致电时:

var cage2 = container.Resolve<ICage>("cage2");

你跑:

new InjectionFactory(c => c.Resolve<Cage>(new ParameterOverride("animal", new Dog()))));

查看内部c.Resolve<Cage>,当它调用unity创建的对象Cagenew Dog()为IAnimal。但!上面,您注册了类型:

container.RegisterType<ICage, Cage>(new ContainerControlledLifetimeManager());

原来如此!内部c.Resolve<Cage>使用Cage为对象Dog创建无命名注册。并且,当它注册为ContainerControlled时,它保存值,并在您调用时:

var cage = container.Resolve<ICage>();

你得到了价值,已经创造了!

固定解决方案:

[TestClass]
public class UnityTest
{
    [TestMethod]
    public void MyTest()
    {
        var container = new UnityContainer();

        // Default registrations for IAnimal and ICage
        container.RegisterType<IAnimal, Cat>(new ContainerControlledLifetimeManager());
        container.RegisterType<ICage, Cage>(new ContainerControlledLifetimeManager());

        container.RegisterType<ICage>(
            "cage2",
            new ContainerControlledLifetimeManager(),
            new InjectionFactory(c => new Cage(new Dog())));

        // Resolve ICage using the named registraion "cage2"
        var cage2 = container.Resolve<ICage>("cage2");
        Assert.AreEqual("Canis lupus", cage2.Animal.Species); // Assert succeeds
        // Resolve default
        var cage = container.Resolve<ICage>();
        Assert.AreEqual("Felis catus", cage.Animal.Species); // Assert succeeds
    }
}