Unity RegisterType与LifetimeManager的奇怪行为

boa*_*des 5 c# inversion-of-control unity-container

我一直在使用Unity容器,并注意到一个奇怪的行为.我有一个类,它实现了多个接口.我希望这个类可以在不同生命周期的应用程序中的不同位置使用.所以我将IFooDerived1映射到Foo作为Singleton,将IFooDerived2映射到Foo作为Transient.但任何Foo的注册都会破坏以前的Foo注册.

样品:

    interface IFoo { }
    interface IFooDerived1 { }
    interface IFooDerived2 { }
    class Foo : IFoo, IFooDerived1, IFooDerived2 { }

    static void Main(string[] args)
    {
        var container = new UnityContainer();

        container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager());
        container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager());
        container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager());

        foreach(var r in container.Registrations)
        {
            Console.WriteLine("{0} -> {1} : {2}", r.RegisteredType.Name, r.MappedToType.Name, r.LifetimeManagerType.Name);
        }
    }
Run Code Online (Sandbox Code Playgroud)

输出:

    IFoo -> Foo : TransientLifetimeManager
    IFooDerived1 -> Foo : TransientLifetimeManager
    IFooDerived2 -> Foo : TransientLifetimeManager
Run Code Online (Sandbox Code Playgroud)

这是正确的行为吗?有人能给出一些合乎逻辑的解释吗?我可以轻松地使用其他一些方法,我只想了解为什么会发生这种情况.谢谢.

Ste*_*ven 2

如果您将注册更改为以下内容:

container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager());
container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager());
container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager());
Run Code Online (Sandbox Code Playgroud)

你会得到以下输出:

    IFoo -> Foo : ExternallyControlledLifetimeManager
    IFooDerived1 -> Foo : ExternallyControlledLifetimeManager
    IFooDerived2 -> Foo : ExternallyControlledLifetimeManager
Run Code Online (Sandbox Code Playgroud)

瓦特?无论您检索什么抽象,您都将始终获得相同的实例。因此,只需更改注册顺序,您就会获得完全不同的生活方式行为。

顺便说一句,这ExternallyControlledLifetimeManager太可怕了,因为它使用了对对象的弱引用,并且可以在应用程序不再保留对它的引用后重新创建它。你几乎不应该采用这种生活方式。

我正在尝试解决这个问题,但似乎在 Unity 中,当您进行注册时,您实际上是在以某种生活方式注册实现,并且提供的抽象仅映射到该注册。因此,如果我们为 Unity 定义一个替代 API,注册将变成这样:

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager());
MapToEntry(from: typeof(IFoo), to: typeof(Foo));
Run Code Online (Sandbox Code Playgroud)

因此,通过这个“替代”API,可以更清楚地看出以下情况正在发生:

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager());
MapToEntry(from: typeof(IFoo), to: typeof(Foo));
MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager());
MapToEntry(from: typeof(IFooDerived1), to: typeof(Foo));
MakeEntry(typeof(Foo), new TransientLifetimeManager());
MapToEntry(from: typeof(IFooDerived2), to: typeof(Foo));
Run Code Online (Sandbox Code Playgroud)

这意味着存在相同的三个条目Foo,显然 Unity 只是默默地接受这一点,最后一个调用获胜。你不讨厌这种隐晦的行为吗?

也许是时候换个图书馆了?