C# JIT 编译器是否优化空值检查?

Does C# JIT compiler optimize null-check?

网上有很多文章列出了C# JIT在执行一段代码之前所做的优化。例如 this post 在 MSDN 上谈到:

Constant folding, Constant and copy propagation, Common subexpression elimination, Code motion of loop invariants, Dead store and dead code elimination, Register allocation, Method inlining, Loop unrolling (small loops with small bodies).

我的问题是:JIT 编译器是否也处理无用的空值检查?我找不到任何来源来处理这个问题。

在我阅读的同一篇文章中:

since the C# language specification ensures that any call on a null object reference throws a NullReferenceException, every call site must ensure the instance is not null. This is done by dereferencing the instance reference; if it is null it will generate a fault that is turned into this exception.

所以,假设我写了一段这样的代码:

if (person != null)
{
    Console.WriteLine(person.Name);
}

person.Name 再次调用显然无用的第二个空检查,编译器可以将其删除。还是不行?

我在 Java 中读到这已经完成(许多 here, here and here 之间的一些来源)。

如果 C# 也这样做,您是否知道一些关于它的来源或文档?

如果 C# 不这样做,您知道为什么吗?在 Java JIT 不会遇到的 .NET 环境中实现这样的功能是否存在内在困难?

Null 检查编译器完成的优化(Roslyn,而不是 Jitter)in several cases,当它完全保存时。

例如,当您使用 ?(猫王运算符)时。

IL_0006: stloc.0              // Pop a value from stack into local variable 0
IL_0007: ldloc.0              // Load local variable 0 onto stack
IL_0008: brtrue.s IL_000c     // Branch to target if value is non-zero (true), short form
IL_000a: br.s IL_0013         // Branch to target, short form
IL_000c: ldloc.0              // Load local variable 0 onto stack
IL_000d: call instance void Foo::Bar() // Call method indicated on the stack with arguments

另一个例子是这样的代码:

new Bar().Foo();

编译器为这个 call 指令而不是 callvirt 生成(这意味着,this 没有空检查)

在其他情况下,您无法确定 this 不会为空。

不管怎样,空值检查真的很快。