一位同事向我展示了一个非常奇怪的行为,我想知道是否有人能解释为什么。
具有2个字符串参数的基本构造函数:
public MyClass(string str1, string str2)
{
this.s1 = str1;
this.s2 = str2;
this.s3 = Method(str2 + "._className", str1);
}
方法是:
public string Method(string key, string defaultValue)
{
List<string> list = _vars[key];
if (list == null) return defaultValue;
string res = "";
foreach (string s in list)
{
if (res != "") res += ",";
res += s;
}
return res;
}
当在将str2
作为null
的aspx页面中调用此ctor时,一切正常,因为如果字符串串联+
的操作数是null
,则会替换空字符串。
但是,当在后台线程中用str2
作为null
调用此ctor时,就会触发NullReferenceException
。
这个问题是通过在使用str2 != null
之前测试它来解决的,但我真的很想知道为什么同一个代码有时会引发异常,有时不会!
这是堆栈跟踪:
Exception: System.NullReferenceException
Message: Object reference not set to an instance of an object.
StackTrace:
at MyClass..ctor(String str1, String str2)
at AbandonedCartsNotificationJob.NotifyAbandonedCarts() in AbandonedCartsNotificationJobPartial.cs:line 39
at AbandonedCartsNotificationJob.work() in AbandonedCartsNotificationJob.cs:line 15
at MyRuntime.JobManager.run()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
在.NET Framework的字符串连接实现中存在一个模糊的错误,但它只影响了4个对象的连接,其中一个对象是非null,提供了返回null的ToString
的重写。显然,这里的情况并非如此。
这种情况很可能是由以下原因之一引起的:
- 调用
Method
时_vars
为空 - 由于在多线程应用程序中滥用
_vars
,_vars
的内部状态已损坏,在使用运算符[]
时导致NullReferenceException
问题在于Method
对象的实现。由于+运算符实现将空值解释为空字符串。在str2
中设置时,实际值null永远不会进入构造函数。在相反方,str1
直接作为null值输入,并可能根据实现情况导致null引用异常。