对象引用没有设置为一个对象的实例。为什么.NET不显示哪个对象是`null`?
关于这个.NET未处理的exception消息:
你调用的对象是空的。
为什么.NET不显示哪个对象为null
?
我知道我可以检查null
并解决错误。 但是,为什么不帮助指出哪个对象有一个空引用,哪个expression式触发了NullReferenceException
?
(有关Visual Studio 2017中新的exception帮助程序的信息,请参阅此答案的结尾)
考虑这个代码:
String s = null; Console.WriteLine(s.Length);
这将在第二行中抛出一个NullReferenceException
,并且你想知道为什么.NET不会在抛出exception时告诉你它是null。
要理解为什么你不能得到这样的信息,你应该记住,它不是C#源代码执行,而是IL:
IL_0001:ldnull IL_0002:stloc.0 // s IL_0003:ldloc.0 // s IL_0004:callvirt System.String.get_Length IL_0009:调用System.Console.WriteLine
它是抛出NullReferenceException
的callvirt
操作码,当评估堆栈上的第一个参数是一个空引用(使用ldloc.0
加载的ldloc.0
)时,它ldloc.0
。
如果.NET应该能够告诉它它是一个空引用,它应该以某种方式跟踪评估堆栈的第一个参数源于s
。 在这种情况下,我们很容易发现它是空的,但是如果该值是来自另一个函数调用的返回值而不是存储在任何variables中呢? 无论如何,这种信息不是你想在虚拟机如.NET虚拟机中追踪的信息。
为了避免这个问题,我build议你在所有的公共方法调用中执行参数null检查(除非你允许空引用):
public void Foo(String s) { if (s == null) throw new ArgumentNullException("s"); Console.WriteLine(s.Length); }
如果将null传递给方法,则会得到一个精确描述问题的exception( s
为null)。
四年后,Visual Studio 2017现在有了一个新的exception帮助程序,当抛出NullReferenceException
时,它将尝试告诉什么是null。 当它是空方法的返回值时,它甚至能够给你所需的信息:
请注意,这只适用于DEBUG版本。
你想如何在下面的情况下的错误消息看起来像?
AnyObject.GetANullObject().ToString(); private object GetANullObject() { return null; }
没有variables名称在这里报告!
那么,微软的工程师就可以回答。 但是,你显然可以使用一个debugging器,并添加手表来找出哪些有问题。
但是, NullReferenceException
exception意味着引用不存在 。 您无法获取尚未创build的对象。
but why .NET don't tell us which object is null?
因为它不知道哪个对象是空的。 该对象根本不存在!
当我说C#被编译为.NET IL代码时也是如此。 .NET IL代码不知道名称或expression式。 它只知道参考和他们的位置。 在这里,你也不能得到不存在的东西。 expression式或variables名称不存在。
哲学:如果你一开始没有蛋,你就不能制作蛋糕。
好问题。 消息框只是没用的。 即使它被埋在参考定义的一英里深处,某些类或程序集或文件或其他信息会比他们目前所提供的更好(阅读:比没有更好)。
您最好的select是在debugging器中运行debugging信息,IDE将在违规行中断开(相当清楚地表明有用的信息实际上是可用的)。