我在多线程环境中遇到以下类的问题:
public class Foo
{
[Inject]
public IBar InjectedBar { get; set; }
public bool NonInjectedProp { get; set; }
public void DoSomething()
{
/* The following line is causing a null-reference exception */
InjectedBar.DoSomething();
}
public Foo(bool nonInjectedProp)
{
/* This line should inject the InjectedBar property */
KernelContainer.Inject(this);
NonInjectedProp = nonInjectedProp;
}
}
这是一个遗留类,这就是我使用属性而不是构造函数注入的原因。
有时,当调用DoSomething()时,InjectedBar属性为null。在单线程应用程序中,一切运行正常。
如何发生这种情况,我该如何预防?
虽然我已经从NInject.Web项目中复制了KernelContainer,但我使用的是没有任何扩展的NInject 2.0。
我注意到我的网络服务中出现了类似的问题。这个问题极其间歇,难以复制。
答案 0 :(得分:2)
首先,我要说这在很多层面都是错误的; KernelContainer
是一个基本上 的基础结构类,可以解决ASP.NET WebForms页面生命周期中的某些限制。它从未打算用在应用程序代码中。使用Ninject内核(或任何DI容器)作为服务定位器is an anti-pattern。
话虽这么说,Ninject本身绝对是线程安全的,因为它一直用于在ASP.NET中为并行请求提供服务。无论这个NullReferenceException
来自哪里,它与Ninject几乎无关。
我可以想到两种可能性:
您必须在某处初始化KernelContainer.Kernel
,并且 代码可能具有竞争条件。如果在内核完全初始化之前尝试使用KernelContainer
(如果您使用IKernel.Bind
方法而不是按照指导加载模块,则可能),您将收到这样的错误。或者:
这是您的IBar
实施本身存在问题,而NullReferenceException
正在DoSomething
方法内的某处发生。当你得到异常时,你实际上没有指定InjectedBar
是null
,所以这是合法的可能性。
为了缩小可能性范围,我首先要消除KernelContainer
。如果您绝对必须使用Ninject作为服务定位器,因为遗留架构设计不佳,那么至少允许它创建依赖关系而不是依赖Inject(this)
。也就是说,无论哪个类或类需要创建您的Foo
,让 类调用kernel.Get<Foo>()
,并将内核设置为{ {1}}。