在线上有很多文章列出了在执行一段代码之前C#JIT所做的优化。例如,MSDN上的this post谈论:
常量折叠,常量和复制传播,公共子表达式 消除,循环不变量的代码运动,死存储和死代码 消除,寄存器分配,方法内联,循环展开 (小身体的小环)。
我的问题是:JIT编译器是否还处理无用的空值检查?我找不到任何来源来处理这个问题。
在同一篇文章中我读到:
因为C#语言规范确保对null的任何调用 对象引用抛出NullReferenceException,每个调用站点都必须 确保实例不为null。这是通过解除引用来完成的 实例参考;如果为null,则会产生故障 变成了这个例外。
所以,假设我写了一段这样的代码:
if (person != null)
{
Console.WriteLine(person.Name);
}
person.Name
再次调用第二个无效的空检查,编译器可以删除它。或者不是?
我在Java中读到这已经完成了(很多here,here和here之间的某些来源。)
如果C#也这样做了,你知道一些谈论这个的来源或文档吗?
如果C#没有这样做,你知道为什么吗?在Java JIT没有遇到的.NET环境中实现这样的功能是否存在内在的困难?
答案 0 :(得分:3)
Null
检查编译器完成的优化(Roslyn,而不是Jitter)in several cases,当它完全保存时。
例如,当您使用?
(Elvis运算符)时。
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
不会为空。
无论如何,空检查真的很快。