c# - Unity RegisterType 与 LifetimeManager 奇怪的行为

标签 c# inversion-of-control unity-container

我一直在使用 Unity 容器并注意到一个奇怪的行为。我有一个类,它实现了多个接口(interface)。我希望此类在具有不同生命周期的应用程序的不同位置使用。所以我已经将 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);
        }
    }

输出:

    IFoo -> Foo : TransientLifetimeManager
    IFooDerived1 -> Foo : TransientLifetimeManager
    IFooDerived2 -> Foo : TransientLifetimeManager

这是正确的行为吗?任何人都可以给出一些合乎逻辑的解释吗?我可以很容易地使用其他一些方法,我只是想了解为什么会这样。谢谢。

最佳答案

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

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

您将获得以下输出:

    IFoo -> Foo : ExternallyControlledLifetimeManager
    IFooDerived1 -> Foo : ExternallyControlledLifetimeManager
    IFooDerived2 -> Foo : ExternallyControlledLifetimeManager

什么?无论你检索什么抽象,你总是会得到相同的实例。因此,只需更改注册顺序,您就会获得完全不同的生活方式。

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

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

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager());
MapToEntry(from: typeof(IFoo), to: typeof(Foo));

因此,使用这个“替代”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));

这意味着同一个 Foo 有三个条目,显然 Unity 只是默默地接受它,最后一个调用获胜。你不讨厌这种含蓄的行为吗?

也许是时候切换到不同的库了?

关于c# - Unity RegisterType 与 LifetimeManager 奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26025999/

相关文章:

DLL 应用程序中的 C# DispatcherTimer 从未触发

java - Spring使用ref标签的本地属性引用存在于其他xml中的bean

java - I18N 属性上的 org.springframework.context.NoSuchMessageException

wcf - 在 Azure Webrole OnStart 中保存时,HttpRuntime.Cache 对象为 null

c# - 混合 Unity Web API 和 MVC4 UnityDependencyResolvers : No parameterless constructor defined for this object

c# - 用多个 byte[] 填充一个 byte[]

c# - 为什么本地化不起作用

c# - 为什么 'Any CPU (prefer 32-bit)' 允许我在 .NET 4.5 下分配比 x86 更多的内存?

dependency-injection - 通过构造函数或属性 setter 进行依赖注入(inject)?

c# - 如何在主容器中注册类型,但在子容器中解析?