对象引用未设置为对象的实例.为什么.NET不显示哪个对象为"null"?

103 .net c#

关于这个.NET未处理的异常消息:

你调用的对象是空的.

为什么.NET不显示哪个对象null

我知道我可以检查null并解决错误.但是,为什么.NET没有帮助指出哪个对象具有空引用以及哪个表达式触发了NullReferenceException

Mar*_*age 169

(有关Visual Studio 2017中新的异常帮助程序的信息,请参阅此答案的结尾)


考虑以下代码:

String s = null;
Console.WriteLine(s.Length);
Run Code Online (Sandbox Code Playgroud)

这将抛出NullReferenceException第二行,你想知道为什么.NET没有告诉你,s抛出异常时它是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:  call        System.Console.WriteLine

它是callvirt抛出的操作码,NullReferenceException当评估堆栈上的第一个参数是空引用(使用加载的参数)时,它会执行此操作ldloc.0.

如果.NET应该能够告诉它是s一个空引用,它应该以某种方式跟踪评估栈的第一个参数来源于表单s.在这种情况下,我们很容易看到它是snull,但是如果值是来自另一个函数调用的返回值并且没有存储在任何变量中该怎么办?无论如何,这种信息不是您想要在.NET虚拟机之类的虚拟机中跟踪的信息.


为了避免这个问题,我建议你在所有公共方法调用中执行参数null检查(除非你允许空引用):

public void Foo(String s) {
  if (s == null)
    throw new ArgumentNullException("s");
  Console.WriteLine(s.Length);
}
Run Code Online (Sandbox Code Playgroud)

如果将null传递给该方法,则会得到一个异常,该异常可以准确地描述问题所在(s即为null).


四年后,Visual Studio 2017现在有了一个新的异常助手,它将尝试在抛出时告诉什么是null NullReferenceException.当它是null的方法的返回值时,它甚至能够为您提供所需的信息:

Visual Studio 2017异常助手

请注意,这仅适用于DEBUG构建.

  • 行号和源文件名也不存储在IL代码本身中,或者它们是什么?然而,它们可以用于调试. (5认同)
  • @MartinLiversage:没错.所以问题可以归结为:为什么符号文件中没有足够的信息也能告诉代码中的哪个表达式被评估为"null". (4认同)
  • 嗯,我们不应该忘记它甚至不是实际执行的IL,而是在运行时从它构建的本机代码. (3认同)
  • @MartinLiversage:可以通过某种方式访问​​符号文件,以便在异常时和异常消息一起,源文件和行号可以显示在调试器的输出中.所以,问题是,没有包含更多关于究竟返回"null"的信息的原因是什么 - 注意OP并不声称他或她想知道对于发布版本,调试版本可能就足够了. (2认同)
  • @MartinLiversage:在这个问题中没有人声称我们希望发布版本完全支持这一点.无论如何,我没有看到将使用对象引用的IL操作码(可能结果为"null")与返回该对象引用的源文件行和列相关联的问题. (2认同)
  • @MartinLiversage:实际上,AFAIK实现`NullReferenceException`确实依赖于引发的硬件错误.有关更多详细信息,请参阅此问题:[为什么在最低地址空间(尽管非空)中的内存访问由.NET报告为NullReferenceException?](http://stackoverflow.com/questions/7940492/why-is-memory-访问中最最低的地址空间非空虽然报-AS-N) (2认同)

rom*_*mar 9

您希望以下情况中的错误消息如何?

AnyObject.GetANullObject().ToString();

private object GetANullObject()
{
  return null;
}
Run Code Online (Sandbox Code Playgroud)

这里没有变量名称要报告!

  • 我怀疑OP正在寻找返回null的源代码中的表达式,而不是对象.我已经对这个问题添加了相应的评论,并希望他或她能清理一下.如果我的怀疑是正确的,OP会期望从AnyObject.GetANullObject()获取的对象引用未设置为对象的实例.作为错误消息. (2认同)