c# - 是否有 C# 代码可以直接在对象引用上调用 `brtrue`/`brfalse` 指令的空检查功能?

标签 c# .net cil opcode

如果标题有意义,请跳到我的问题部分。如果没有,这里有一些背景信息。

我正在编写一些代码,它碰巧使用了空合并运算符。 我的代码:

_handle = handle ?? throw new ArgumentNullException (nameof(handle));

_handlehandle 都是 class Handle 类型(我编写的)。

我决定调查 IL。这是它输出的内容:

...
IL_0002: ldarg.1      // handle
IL_0003: dup          
IL_0004: brtrue.s     IL_0012   // transfer to line that stores into _handle
IL_0006: pop          
IL_0007: ldstr        "handle"
IL_000c: newobj       instance void [mscorlib]System.ArgumentNullException::.ctor(string)
IL_0011: throw        
IL_0012: stfld        class Sandbox.V1.Handle Sandbox.V1.Spade::_handle
...

我在这里看到brtrue.s(或者它可能是代码略有不同的brfalse.s)指令(IL_0004)并没有真正检查handle 引用等于(或不等于)null (ldnull)。
相反,它直接在 handle 引用上调用 brfalse

换句话说,它一开始并没有做这样的事情:

...
IL_0001: ldarg.1      // handle
IL_0002: ldnull       
IL_0003: ceq          
IL_0004: brfalse.s    IL_0012   // transfer to line that stores into _handle
...

当然,第二种方法会生成更多的IL代码,但为了这个问题,我只输入了相关部分。

问题:
1)这两种方法之间是否存在任何可测量的差异?
第一种方法(编译器对上面的 C# 代码执行的操作)直接在对象引用上调用 brtrue/false),而第二种方法则在对象与 ldnull 的比较结果(这是编译器通过 == null 检查生成的结果)。
据我了解,第一种方法至少少处理一条指令,因此在某种程度上,这是可以衡量的。
2) 如果是这样,有没有办法强制编译器为 C# 中的空检查生成此类 IL?
即在 C# 中编写与 myObj != null 等效的代码,其中生成的 IL 直接在 myObj 引用上调用 brtrue.s

或者我错过了一些基本的东西吗? IL 不是我的最强项。
我也愿意接受有人合理地说服我,我只是在这里疯了:)

提前致谢!

最佳答案

正如评论中提到的,IL 只是代码执行时实际运行的一部分。因此,关于您问题的第一部分,ldnull/ceq 版本较长这一事实自然意味着它需要稍微更长的时间加载到内存中,还有更多的指令供 JIT 分析并编译为 native 代码。

然而,鉴于差异非常微小,这些差异基本上可以忽略不计,并且由于它们是一次性事件,因此实际上与 JIT-ted 方法实际运行时的性能无关。为此,我们需要查看当该方法经过 JIT 处理时实际生成了哪些指令以及是否存在任何差异。

为此,我将两个动态方法组合在一起,显式发出所需的 IL,并检查 JIT 为两个版本生成的 native 代码。

结果可能毫不奇怪地相同(具体来说,测试 XXX,XXX 后跟 je ...),因此显然 JIT 有能力识别这些结果IL 的模式,并在发出 native 代码时以相同的方式处理它们。

对于问题的第二部分,如 answer from InBetween表示一旦在 Release 模式下编译,生成的 IL 之间的差异就会消失,并且都使用较短的 brfalse/brtrue 方法。

关于c# - 是否有 C# 代码可以直接在对象引用上调用 `brtrue`/`brfalse` 指令的空检查功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51229737/

相关文章:

c# - 如何为 VisualStudio2015 设置 .NET 版本(代码)

c# - 在加载项中使用 Visual Studio 主题

c# - 我应该如何连接字符串?

c# - StreamWriter 不创建新文件

c# - 带有 CIL 代码编译器的 Antlr

.net - "<Module>"类型是什么?

c# - 通过Azure Function处理多个请求

c# - 为什么 VS2010 总是在 MethodInfo.Invoke 异常时中断?

.net - “Code Access Security” 在现实世界中有用吗?

c# - 如何验证 C# 代码?