C# 未将对象引用设置为对象的实例。为什么 .NET 不显示哪个对象是 `null`?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14787580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 12:59:27  来源:igfitidea点击:

Object reference not set to an instance of an object.Why doesn't .NET show which object is `null`?

c#.net

提问by

Regarding this .NET unhandled exception message:

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

Object reference not set to an instance of an object.

你调用的对象是空的。

Why doesn't .NET show which object is null?

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

I know that I can check for nulland resolve the error. However, why doesn't .NET help pointing out which object has a null-reference and which expression triggered the NullReferenceException?

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

采纳答案by Martin Liversage

(For information about the new exception helper in Visual Studio 2017 see the end of this answer)

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



Consider this code:

考虑这个代码:

String s = null;
Console.WriteLine(s.Length);

This will throw a NullReferenceExceptionin the second line and you want to know why .NET doesn't tell you that it was sthat was null when the exception was thrown.

这将NullReferenceException在第二行中抛出 a并且您想知道为什么 .NETs在抛出异常时没有告诉您它是 null。

To understand why you don't get that piece of information you should remember that it is not C# source that executes but rather IL:

要理解为什么您没有得到那条信息,您应该记住执行的不是 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

It is the callvirtopcode that throws the NullReferenceExceptionand it does that when the first argument on the evaluation stack is a null reference (the one that was loaded using ldloc.0).

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

If .NET should be able to tell that it was sthat was a null reference it should in some way track that the first argument on the evaluation stack originated form s. In this case it is easy for us to see that it is sthat was null but what if the value was a return value from another function call and not stored in any variable? Anyway, this kind of information is not what you want to keep track of in a virtual machine like the .NET virtual machine.

如果 .NET 应该能够判断这s是一个空引用,它应该以某种方式跟踪求值堆栈上的第一个参数源自表单s。在这种情况下,我们很容易看到它是snull 但是如果该值是另一个函数调用的返回值而不存储在任何变量中呢?无论如何,这种信息不是您想要在像 .NET 虚拟机这样的虚拟机中跟踪的信息。



To avoid this problem I suggest that you perform argument null checking in all public method calls (unless of course you allow the null reference):

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

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

If null is passed to the method you get an exception that precisely describes what the problem is (that sis null).

如果将 null 传递给该方法,您会得到一个异常,该异常准确地描述了问题所在(即snull)。



Four years later Visual Studio 2017 now has a new exception helper that will try to tell what is null when a NullReferenceExceptionis thrown. It is even able to give you the required information when it is the return value of a method that is null:

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

Visual Studio 2017 exception helper

Visual Studio 2017 异常帮助程序

Note that this only works in a DEBUG build.

请注意,这仅适用于调试版本。

回答by romar

How do you want the error message in the following case look like?

您希望以下情况下的错误消息是什么样的?

AnyObject.GetANullObject().ToString();

private object GetANullObject()
{
  return null;
}

No variable names to report here!

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

回答by Aniket Inge

Well, that's upto engineers at Microsoft to answer. But you can obviously use a debugger and add watch to find out which of those has a problem.

嗯,这由微软的工程师来回答。但是您显然可以使用调试器并添加 watch 来找出哪些有问题。

However, the exception is NullReferenceExceptionwhich means the reference does not exist. You can't get the object which hasn't been created at all.

但是,例外情况是NullReferenceException这意味着引用不存在。您根本无法获取尚未创建的对象。

but why .NET don't tell us which object is null?Because it does not know which object is null. The object simply does not exist!

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

Same is the case when I say, C# is compiled to .NET IL code. The .NET IL code does not know the names or expressions. It only knows references and their location. Here too, you cannot get what does not exist. The expression or the variable name does not exist.

我说的情况也是如此,C# 被编译为 .NET IL 代码。.NET IL 代码不知道名称或表达式。它只知道引用及其位置。在这里,你也无法得到不存在的东西。表达式或变量名称不存在。

Philosophy: You cannot make an omlette if you don't have an egg in the first place.

理念:如果您首先没有鸡蛋,您就无法制作煎蛋卷。

回答by Rick O'Shea

Good question. The message box is just short of useless. Even if it's buried a mile deep from the references definition, some class or assembly or file or other information would be better than what they currently provide (read: better than nothing).

好问题。消息框几乎没用。即使它与引用定义相距一英里深,某些类或程序集或文件或其他信息也会比它们当前提供的更好(阅读:总比没有好)。

Your best option is to run it in the debugger with debugging information, and your IDE will break at the offending line (rather clearly demonstrating that useful information is in fact available).

您最好的选择是在带有调试信息的调试器中运行它,您的 IDE 将在违规行处中断(而是清楚地表明有用信息实际上是可用的)。

回答by oniel telies

Not sure, but this may be because .Net doesn't knows whether it is predefined class or user-defined. If it is predefined then it can be null(like string which occupies 2 Bytes) but if it is user-defined than we have to create an instance of it so that it knows that this object will occupy this much memory. So therefore it throws error at run-time.

不确定,但这可能是因为 .Net 不知道它是预定义的类还是用户定义的。如果它是预定义的,那么它可以为空(就像占用 2 个字节的字符串),但如果它是用户定义的,那么我们必须创建它的一个实例,以便它知道这个对象将占用这么多内存。因此,它会在运行时引发错误。