“对象引用未设置为对象的实例”:为什么.NET不能显示更多细节?

时间:2021-09-19 02:35:39

"Object reference not set to an instance of an object"

“你调用的对象是空的”

Why does the exception not also show the name of the object reference field, or at least its type?

为什么异常不会显示对象引用字段的名称,或者至少显示其类型?

This is probably one of the most common run-time errors in .NET. Although the System.Exception has a stack trace, there are no other helpful details.

这可能是.NET中最常见的运行时错误之一。尽管System.Exception具有堆栈跟踪,但没有其他有用的详细信息。

Over the course of a year I spend hours sifting through stack traces (often in code I did not write), hoping there is a line number from a ".pdb" file, then finding the line in the code, and even then it is often not obvious which reference on the line was null. Having the name of the reference field would be very convenient.

在一年的过程中,我花了几个小时筛选堆栈跟踪(通常在代码中我没写),希望有一个来自“.pdb”文件的行号,然后在代码中查找行,即使这样,它也是通常不明显该线上的哪个引用为null。拥有参考字段的名称将非常方便。

If System.ArgumentNullException instances can show the name of the method parameter ("Value cannot be null. Parameter name: value"), then surely System.NullReferenceException instances could include the name of the null field (or its containing collection).

如果System.ArgumentNullException实例可以显示方法参数的名称(“值不能为null。参数名称:值”),那么System.NullReferenceException实例肯定可以包含空字段(或其包含集合)的名称。

4 个解决方案

#1


7  

The difference between ArgumentNullException and NullReferenceException is that ArgumentNullException is always thrown explicitly like so:

ArgumentNullException和NullReferenceException之间的区别在于ArgumentNullException总是被显式抛出,如下所示:

if (parameter == null)
  throw new ArgumentNullException("parameter");

Had a quick look at ILDASM output, the local variables are indeed present inside a function's IL. There is still, however, no API to retrieve those names programatically. My understanding is that it would be fairly complex as you would basically need to build a parse tree that represents a function with scopes, variables, statements etc.

快速查看ILDASM输出,局部变量确实存在于函数的IL中。但是,仍然没有API以编程方式检索这些名称。我的理解是它会相当复杂,因为你基本上需要构建一个解析树来表示一个带有范围,变量,语句等的函数。

It's further complicated by the fact that it's not just simple variables that can throw NullReferenceException, but result of a function call, a property or an expression. I could get pretty complicated pretty fast.

更复杂的是,它不仅仅是可以抛出NullReferenceException的简单变量,而是函数调用,属性或表达式的结果。我可以很快地变得非常复杂。

Imagine this:

internalObject.OtherProperty = myObject.GetOtherObject().ThirdObject.SomeProperty == "value"
 ? myObject.OtherProperty
 : myObject.GetSomethingElse();

There are multiple points of failure there and building up a string representing what is actually null could be tricky.

那里有多个失败点,并且构建一个表示实际为null的字符串可能很棘手。

#2


2  

This has been covered here: Detecting what the target object is when NullReferenceException is thrown

这里已经介绍过:在抛出NullReferenceException时检测目标对象是什么

and here: Why can't a null-reference exception name the object that has a null reference?

在这里:为什么空引用异常不能命名具有空引用的对象?

The reason is mainly cause the runtime has no idea when the NRE is encountered. My guess it that it would have to work back the callstack and through the parse tree, which would be really expensive.

原因主要是因为运行时不知道何时遇到NRE。我猜它必须回复callstack并通过解析树,这将是非常昂贵的。

#3


1  

Even though the variable name and type may exist in the MSIL code, it won't exist in the native code when the MSIL is JITted.

尽管变量名称和类型可能存在于MSIL代码中,但当MSIL被JIT时,它不会存在于本机代码中。

It would be incredibly inefficient to add this kind of check to the native code during JITting - essentially an overhead whenever a pointer is dereferenced.

在JITting期间将这种检查添加到本机代码是非常低效的 - 当指针被取消引用时,本质上是一种开销。

#4


0  

I did not find this exception that hard to deal with!

我没有发现这个难以处理的异常!

If I know the line number. I just insert a breakpoint at this line, run the application to this line, and when the debugger stops, I hover every variable/object in the line, and thanks to Visual Studio, it shows me their values.

如果我知道行号。我只是在这一行插入一个断点,运行应用程序到这一行,当调试器停止时,我将每个变量/对象悬停在该行中,并且由于Visual Studio,它向我显示了它们的值。

Also I found Autos window very helpful in such cases, but the procedure I described above solves my problem quickly.

此外,我发现Autos窗口在这种情况下非常有用,但我上面描述的过程很快就解决了我的问题。

#1


7  

The difference between ArgumentNullException and NullReferenceException is that ArgumentNullException is always thrown explicitly like so:

ArgumentNullException和NullReferenceException之间的区别在于ArgumentNullException总是被显式抛出,如下所示:

if (parameter == null)
  throw new ArgumentNullException("parameter");

Had a quick look at ILDASM output, the local variables are indeed present inside a function's IL. There is still, however, no API to retrieve those names programatically. My understanding is that it would be fairly complex as you would basically need to build a parse tree that represents a function with scopes, variables, statements etc.

快速查看ILDASM输出,局部变量确实存在于函数的IL中。但是,仍然没有API以编程方式检索这些名称。我的理解是它会相当复杂,因为你基本上需要构建一个解析树来表示一个带有范围,变量,语句等的函数。

It's further complicated by the fact that it's not just simple variables that can throw NullReferenceException, but result of a function call, a property or an expression. I could get pretty complicated pretty fast.

更复杂的是,它不仅仅是可以抛出NullReferenceException的简单变量,而是函数调用,属性或表达式的结果。我可以很快地变得非常复杂。

Imagine this:

internalObject.OtherProperty = myObject.GetOtherObject().ThirdObject.SomeProperty == "value"
 ? myObject.OtherProperty
 : myObject.GetSomethingElse();

There are multiple points of failure there and building up a string representing what is actually null could be tricky.

那里有多个失败点,并且构建一个表示实际为null的字符串可能很棘手。

#2


2  

This has been covered here: Detecting what the target object is when NullReferenceException is thrown

这里已经介绍过:在抛出NullReferenceException时检测目标对象是什么

and here: Why can't a null-reference exception name the object that has a null reference?

在这里:为什么空引用异常不能命名具有空引用的对象?

The reason is mainly cause the runtime has no idea when the NRE is encountered. My guess it that it would have to work back the callstack and through the parse tree, which would be really expensive.

原因主要是因为运行时不知道何时遇到NRE。我猜它必须回复callstack并通过解析树,这将是非常昂贵的。

#3


1  

Even though the variable name and type may exist in the MSIL code, it won't exist in the native code when the MSIL is JITted.

尽管变量名称和类型可能存在于MSIL代码中,但当MSIL被JIT时,它不会存在于本机代码中。

It would be incredibly inefficient to add this kind of check to the native code during JITting - essentially an overhead whenever a pointer is dereferenced.

在JITting期间将这种检查添加到本机代码是非常低效的 - 当指针被取消引用时,本质上是一种开销。

#4


0  

I did not find this exception that hard to deal with!

我没有发现这个难以处理的异常!

If I know the line number. I just insert a breakpoint at this line, run the application to this line, and when the debugger stops, I hover every variable/object in the line, and thanks to Visual Studio, it shows me their values.

如果我知道行号。我只是在这一行插入一个断点,运行应用程序到这一行,当调试器停止时,我将每个变量/对象悬停在该行中,并且由于Visual Studio,它向我显示了它们的值。

Also I found Autos window very helpful in such cases, but the procedure I described above solves my problem quickly.

此外,我发现Autos窗口在这种情况下非常有用,但我上面描述的过程很快就解决了我的问题。