我一直在玩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);
}
}
输出:
IFoo -> Foo : TransientLifetimeManager
IFooDerived1 -> Foo : TransientLifetimeManager
IFooDerived2 -> Foo : TransientLifetimeManager
这是正确的行为吗?有人能给出一些合乎逻辑的解释吗?我可以轻松地使用其他一些方法,我只想了解为什么会发生这种情况。感谢。
答案 0 :(得分:1)
如果您将注册更改为以下内容:
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
WAT?无论您检索什么抽象,您都将获得相同的实例。因此,只需改变注册顺序,就可以获得完全不同的生活方式。
顺便说一下,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只是默默地接受这个,最后一个呼叫获胜。你不讨厌这种隐含的行为吗?
是时候切换到不同的图书馆?