关于这个 .NET 未处理的异常消息:
你调用的对象是空的。
为什么.NET 不显示哪个对象是null
?
我知道我可以检查null
并解决错误。但是,为什么 .NET 不帮助指出哪个对象具有空引用以及哪个表达式触发了NullReferenceException
?
(有关 Visual Studio 2017 中新的异常帮助程序的信息,请参阅此答案的结尾)
考虑这段代码:
String s = null;
Console.WriteLine(s.Length);
这将在第二行抛出 aNullReferenceException
并且您想知道为什么 .NET 没有告诉您s
在抛出异常时它是 null。
要了解为什么您没有获得该信息,您应该记住执行的不是 C# 源代码,而是 IL:
IL_0001:ldnull IL_0002: stloc.0 // 秒 IL_0003: ldloc.0 // 秒 IL_0004: callvirt System.String.get_Length IL_0009:调用 System.Console.WriteLine
它是callvirt
抛出 的操作码,NullReferenceException
当评估堆栈上的第一个参数是空引用(使用 加载的那个ldloc.0
)时,它会这样做。
如果 .NET 应该能够判断它s
是一个空引用,它应该以某种方式跟踪评估堆栈上的第一个参数源自表单s
。在这种情况下,我们很容易看出它是s
null 但是如果该值是另一个函数调用的返回值并且没有存储在任何变量中怎么办?无论如何,这种信息不是您想要在 .NET 虚拟机等虚拟机中跟踪的内容。
为了避免这个问题,我建议您在所有公共方法调用中执行参数 null 检查(当然,除非您允许 null 引用):
public void Foo(String s) {
if (s == null)
throw new ArgumentNullException("s");
Console.WriteLine(s.Length);
}
如果将 null 传递给该方法,则会得到一个异常,该异常准确地描述了问题所在(即s
null)。
四年后,Visual Studio 2017 现在有了一个新的异常帮助器,它会在NullReferenceException
抛出 a 时尝试判断什么是 null。当方法的返回值为 null 时,它甚至可以为您提供所需的信息:
请注意,这仅适用于 DEBUG 构建。
您希望以下情况下的错误消息是什么样的?
AnyObject.GetANullObject().ToString();
private object GetANullObject()
{
return null;
}
这里没有要报告的变量名!
嗯,这取决于微软的工程师来回答。但是您显然可以使用调试器并添加监视来找出其中哪些有问题。
但是,例外情况是NullReferenceException
引用不存在。您根本无法获取尚未创建的对象。
but why .NET don't tell us which object is null?
因为它不知道哪个对象是空的。该对象根本不存在!
我说的情况也是如此,C# 被编译为 .NET IL 代码。.NET IL 代码不知道名称或表达式。它只知道引用及其位置。在这里,你也无法得到不存在的东西。表达式或变量名不存在。
理念:如果你一开始就没有鸡蛋,你就不能做煎蛋卷。
不确定,但这可能是因为.Net 不知道它是预定义的类还是用户定义的。如果它是预定义的,那么它可以为空(如占用 2 个字节的字符串),但如果它是用户定义的,那么我们必须创建它的一个实例,以便它知道这个对象将占用这么多内存。因此,它在运行时引发错误。
好问题。消息框简直没用。即使它与引用定义相距一英里,某些类或程序集或文件或其他信息也会比它们当前提供的更好(阅读:总比没有好)。
您最好的选择是在带有调试信息的调试器中运行它,并且您的 IDE 将在有问题的行处中断(更清楚地表明有用的信息实际上是可用的)。