Eam*_*mon 32 c# mscorlib nullreferenceexception
我正在研究一位同事在通过Visual Studio 2010运行应用程序时遇到的异常:
System.NullReferenceException was unhandled by user code
Message=Object reference not set to an instance of an object.
Source=mscorlib
StackTrace:
at System.Collections.Generic.GenericEqualityComparer`1.Equals(T x, T y)
at System.Collections.Concurrent.ConcurrentDictionary`2.TryGetValue(TKey key, TValue& value)
at xxxxxxx.xxxxxxx.xxxxxxx.RepositoryBase`2.GetFromCache(TIdentity id)
Run Code Online (Sandbox Code Playgroud)
使用.NET Reflector,我查看了代码GenericEqualityComparer<T>.Equals(T x, T y),我看不出任何可能的原因NullReferenceException.
//GenericEqualityComparer<T>.Equals(T x, T y) from mscorlib 4.0.30319.269
public override bool Equals(T x, T y)
{
if (x != null)
{
return ((y != null) && x.Equals(y));
}
if (y != null)
{
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
此堆栈跟踪中的类型T, TKey和类型TIdentity都相同.
该类型是一个称为Identity实现的自定义类型IEquatable<Identity>.它是不可变的,不能用它在其实现中使用的字段的空值构造Equals(Identity other).它也覆盖Equals(object obj)如下:
public override bool Equals(object obj)
{
if ((object)this == obj)
{
return true;
}
return Equals(obj as Identity);
}
public bool Equals(Identity other)
{
if ((object)this == (object)other)
{
return true;
}
if ((object)other == null)
{
return false;
}
if (!FieldA.Equals(other.FieldA))
{
return false;
}
return FieldB.Equals(other.FieldB);
}
Run Code Online (Sandbox Code Playgroud)
我对这些Equals实现有一套相当详尽的单元测试.因此,它会愉快地接受其他/ obj的null值,并按预期返回false.
该类型不会覆盖==运算符或!=运算符.
即便如此,我希望看到的堆栈跟踪的顶部我的课,如果该异常正在起实施扔Equals(Identity other)在我的Identity课,但它说的NullReferenceException是来自mscorlib.
我正在运行.NET Framework 4.0.30319.269.
我没有内存转储,我之前没有看过这个,也没有重现过.尽管如此,我仍然有义务进行调查,并且绝对肯定它不是由我们的代码引起的,并且它不会在生产中发生.
所以,真正的问题是:是什么导致了这个例外?
*响应Jordão*的更新
是否可以使用不是Identity的对象调用该方法?
在ConcurrentDictionary<TKey, TValue>键入使得TKey= Identity并没有什么子类Identity.所以,我看不出它是如何可能的.
是否可以使用null调用该方法?
单元测试涵盖了Equals使用null 调用所有实现的场景.
什么版本的代码是堆栈跟踪?也许某些旧版本容易受到例外的影响?
我正在分析生成异常的相同代码.我已经检查过在我的同事计算机上运行的.NET Framework版本也是4.0.30319.269.
任何多线程场景都可能导致异常?这些通常难以复制,但可能值得研究.
是的,代码是多线程的,并且打算成为.所以,这就是我使用的原因ConcurrentDictionary.
*与Jalal Aldeen Saa'd*的回应有关的跟进
我本来以为,其中一些其他线程设置的竞争条件x,以null只能是原因,如果该参数x是通过使用"裁判"关键字引用传递.我开始用以下代码验证该理论:
ManualResetEvent TestForNull = new ManualResetEvent(false);
ManualResetEvent SetToNull = new ManualResetEvent(false);
[TestMethod]
public void Test()
{
var x = new object();
var y = new object();
var t = Task.Factory.StartNew(() =>
{
return Equals(x, y);
});
TestForNull.WaitOne(); //wait until x has been tested for null value
x = null;
SetToNull.Set(); //signal that x has now been set to null
var result = t.Result;
Assert.IsFalse(result);
}
public bool Equals<T>(T x, T y)
{
if (x != null)
{
TestForNull.Set(); //signal that we have determined that x was not null
SetToNull.WaitOne(); //wait for original x value to be set to null
//would fail here if setting the outer scope x to null affected
//the value of x in this scope
return ((y != null) && x.Equals(y));
}
if (y != null)
{
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
并且测试完成且没有错误.
我可以强制行为,如果我更改签名来传递x和y通过引用(即,public bool Equals<T>(ref T x, ref T y) then the test fails with a的NullReferenceException , but this does not match the method signature ofGenericEqualityComparer.Equals(T X,T Y)`.
我将在这里阐述我的假设。
堆栈让您相信这是崩溃发生的地方,但它发生在其他地方。我们正在寻找错误的线索。
我不知道这是否实用,但有时好的旧“printf 调试”会有所帮助。如果您在调用之前打印出您要查找的值怎么办TryGetValue?你会看到你是否击中了空值。
| 归档时间: |
|
| 查看次数: |
2901 次 |
| 最近记录: |