对象引用没有设置为一个对象的实例。为什么.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

它是抛出NullReferenceExceptioncallvirt操作码,当评估堆栈上的第一个参数是一个空引用(使用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。 当它是空方法的返回值时,它甚至能够给你所需的信息:

Visual Studio 2017异常助手

请注意,这只适用于DEBUG版本。

你想如何在下面的情况下的错误消息看起来像?

 AnyObject.GetANullObject().ToString(); private object GetANullObject() { return null; } 

没有variables名称在这里报告!

那么,微软的工程师就可以回答。 但是,你显然可以使用一个debugging器,并添加手表来找出哪些有问题。

但是, NullReferenceExceptionexception意味着引用不存在 。 您无法获取尚未创build的对象。

but why .NET don't tell us which object is null? 因为它不知道哪个对象是空的。 该对象根本不存在!

当我说C#被编译为.NET IL代码时也是如此。 .NET IL代码不知道名称或expression式。 它只知道参考和他们的位置。 在这里,你也不能得到不存在的东西。 expression式或variables名称不存在。

哲学:如果你一开始没有蛋,你就不能制作蛋糕。

好问题。 消息框只是没用的。 即使它被埋在参考定义的一英里深处,某些类或程序集或文件或其他信息会比他们目前所提供的更好(阅读:比没有更好)。

您最好的select是在debugging器中运行debugging信息,IDE将在违规行中断开(相当清楚地表明有用的信息实际上是可用的)。