Unity:如果我试图获得在多个映射中注册的单例,将会得到StackOverflowException
本文关键字:注册 单例 StackOverflowException 映射 如果 Unity | 更新日期: 2023-09-27 17:50:55
给定以下两个接口和一个类:
interface IRepository<T> {}
interface IXRepository : IRepository<MyType> {}
class XRepository : IXRepository {}
我想要一个类型为XRepository
的单例,它可以通过IRepository<MyType>
或IXRepository
来解析。
我以以下代码开始:
public void Register<TFrom, TTo>(params Type[] typesToRegister) where TTo : TFrom
{
parentContainer.RegisterType<TFrom, TTo>(new HierarchicalLifetimeManager());
foreach (Type type in typesToRegister)
{
parentContainer.RegisterType(type, typeof(TTo), new HierarchicalLifetimeManager(), new InjectionFactory(c => c.Resolve<TFrom>()));
}
}
下面是客户端方法调用:
service.Register<IRepository<MyType>, XRepository>(typeof(IXRepository));
执行此语句后的childContainer的注册(标题:RegisteredType, MappedToType, Name和LifetimeManagerType):
-
typeof(IRepository<MyType>)
,typeof(XRepository>)
,null
,typeof(HierarchicalLifetimeManager)
-
typeof(IXRepository)
,typeof(XRepository)
,null
,typeof(HierarchicalLifetimeManager)
但是,如果我试图通过IRepository<MyType>
(或IXRepository
)的方式解决,StackOverflowException将被抛出。这是因为new InjectionFactory(c => c.Resolve<TFrom>())
中的lambda表达式被一次又一次地执行。有人知道这是怎么回事吗?在请求IRepository<MyType>
时执行lambda表达式的原因是什么?
我发现,如果你在注册时提供一个名字("gaga"在这个例子中),不会抛出StackOverflowException:
-
typeof(IRepository<MyType>)
typeof(XRepository>)
,"gaga"
,typeof(HierarchicalLifetimeManager)
-
typeof(IXRepository)
,typeof(XRepository)
,null
,typeof(HierarchicalLifetimeManager)
谢谢,罗杰
您可以将具体类型XRepository
注册为单例,然后注册要用该类型解析的两个接口:
container.RegisterType<XRepository>(new HierarchicalLifetimeManager());
container.RegisterType<IRepository<String>, XRepository>();
container.RegisterType(typeof(IXRepository), typeof(XRepository));
如果你运行下面的代码,你会看到单例行为被应用,并且子容器被考虑在内:
var isSingleton = container.Resolve<IRepository<String>>() == container.Resolve<IXRepository>();
var outerInstance = container.Resolve<IXRepository>();
using(var childContainer = container.CreateChildContainer())
{
isSingleton = childContainer.Resolve<IRepository<String>>() == childContainer.Resolve<IXRepository>();
var isHierarchichalSingleton = outerInstance != childContainer.Resolve<IXRepository>();
}
作为旁注,您的问题可以用更简单的方式复制。这可能是Unity中的一个bug 这是根据Unity的设计(检查@Lukazoid评论和回答),例如:
interface IFoo { }
interface IBar { }
class Foo : IFoo, IBar { }
container.RegisterType<IFoo, Foo>();
container.RegisterType<IBar, Foo>(new InjectionFactory(c => c.Resolve<IFoo>()));
var foo = container.Resolve<IFoo>();
在Unity中使用LifetimeManagers
时,只使用为目标类型指定的最后一个LifetimeManager
。到相同目标类型的多个接口映射都将使用相同的LifetimeManager
,例如
container.RegisterType<IRepository<MyType>, XRepository>(new HierarchicalLifetimeManager());
container.RegisterType<IXRepository, XRepository>();
var first = container.Resolve<IRepository<MyType>>();
var second = container.Resolve<IXRepository>();
Console.WriteLine("Same instance: {0}", ReferenceEquals(first, second));
将输出
相同实例:True
基于这个事实,你的寄存器方法可以像这样改变:
public void Register<TFrom, TTo>(params Type[] typesToRegister) where TTo : TFrom
{
parentContainer.RegisterType<TFrom, TTo>(new HierarchicalLifetimeManager());
foreach (Type type in typesToRegister)
{
parentContainer.RegisterType(type, typeof(TTo));
}
}
下面是演示解决方案的LINQPad示例:http://share.linqpad.net/dbd9hx.linq