C# 返回内部if块与写入if/else块之间是否存在性能差异?
我正在进行重构代码的项目,并意识到我写了如下内容:C# 返回内部if块与写入if/else块之间是否存在性能差异?,c#,performance,if-statement,return,C#,Performance,If Statement,Return,我正在进行重构代码的项目,并意识到我写了如下内容: if(errorCode > 0) { DisplayError(errorCode); return; } // Continue to do stuff otherwise. if (errorCode > 0) { 011A00DA in al,dx 011A00DB push eax 011A00DC mov dword p
if(errorCode > 0)
{
DisplayError(errorCode);
return;
}
// Continue to do stuff otherwise.
if (errorCode > 0) {
011A00DA in al,dx
011A00DB push eax
011A00DC mov dword ptr [ebp-4],ecx
011A00DF cmp dword ptr ds:[10F3178h],0
011A00E6 je 011A00ED
011A00E8 call 7470C310
011A00ED cmp dword ptr [ebp-4],0
011A00F1 jle 011A0100
Console.WriteLine(errorCode);
011A00F3 mov ecx,dword ptr [ebp-4]
011A00F6 call 73C5A920
return;
011A00FB nop
011A00FC mov esp,ebp
011A00FE pop ebp
011A00FF ret
}
Console.WriteLine("ok");
011A0100 mov ecx,dword ptr ds:[3E92190h]
011A0106 call 7359023C
}
011A010B nop
011A010C mov esp,ebp
011A010E pop ebp
011A010F ret
正如您可能猜到的,函数的返回类型为void。当我开始仔细考虑这一点时,我思考将其放在if/else块中是否有真正的区别:
if(errorCode > 0)
{
DisplayError(errorCode);
}
else
{
// Do other stuff
}
else块将一直持续到函数结束,因此控制流基本上是相同的。这里是否存在性能差异,或者是否应该使用约定,或者这两种情况是否完全相同?两种情况下生成的代码完全相同 在第一个示例中,您在代码周围缺少括号,但我将假定这是一个输入错误,您实际上是在询问使用return和else之间的区别 如果查看这两种方法的生成代码:
public static void Test1(int errorCode) {
if (errorCode > 0) {
Console.WriteLine(errorCode);
return;
}
Console.WriteLine("ok");
}
public static void Test2(int errorCode) {
if (errorCode > 0) {
Console.WriteLine(errorCode);
} else {
Console.WriteLine("ok");
}
}
它将如下所示:
if(errorCode > 0)
{
DisplayError(errorCode);
return;
}
// Continue to do stuff otherwise.
if (errorCode > 0) {
011A00DA in al,dx
011A00DB push eax
011A00DC mov dword ptr [ebp-4],ecx
011A00DF cmp dword ptr ds:[10F3178h],0
011A00E6 je 011A00ED
011A00E8 call 7470C310
011A00ED cmp dword ptr [ebp-4],0
011A00F1 jle 011A0100
Console.WriteLine(errorCode);
011A00F3 mov ecx,dword ptr [ebp-4]
011A00F6 call 73C5A920
return;
011A00FB nop
011A00FC mov esp,ebp
011A00FE pop ebp
011A00FF ret
}
Console.WriteLine("ok");
011A0100 mov ecx,dword ptr ds:[3E92190h]
011A0106 call 7359023C
}
011A010B nop
011A010C mov esp,ebp
011A010E pop ebp
011A010F ret
以及:
生成的代码完全相同,一直到最后一条指令。两种情况下生成的代码完全相同 在第一个示例中,您在代码周围缺少括号,但我将假定这是一个输入错误,您实际上是在询问使用return和else之间的区别 如果查看这两种方法的生成代码:
public static void Test1(int errorCode) {
if (errorCode > 0) {
Console.WriteLine(errorCode);
return;
}
Console.WriteLine("ok");
}
public static void Test2(int errorCode) {
if (errorCode > 0) {
Console.WriteLine(errorCode);
} else {
Console.WriteLine("ok");
}
}
它将如下所示:
if(errorCode > 0)
{
DisplayError(errorCode);
return;
}
// Continue to do stuff otherwise.
if (errorCode > 0) {
011A00DA in al,dx
011A00DB push eax
011A00DC mov dword ptr [ebp-4],ecx
011A00DF cmp dword ptr ds:[10F3178h],0
011A00E6 je 011A00ED
011A00E8 call 7470C310
011A00ED cmp dword ptr [ebp-4],0
011A00F1 jle 011A0100
Console.WriteLine(errorCode);
011A00F3 mov ecx,dword ptr [ebp-4]
011A00F6 call 73C5A920
return;
011A00FB nop
011A00FC mov esp,ebp
011A00FE pop ebp
011A00FF ret
}
Console.WriteLine("ok");
011A0100 mov ecx,dword ptr ds:[3E92190h]
011A0106 call 7359023C
}
011A010B nop
011A010C mov esp,ebp
011A010E pop ebp
011A010F ret
以及:
生成的代码完全相同,一直到最后一条指令。离题,但太大,无法发表评论,因为您还可以使用优秀的IL反汇编 有趣的是,仅在调试模式下分解IL时,Guffa的Test2 IL中还有几个额外的IL,根据Guffa的回答,这些IL在x86/x64 JIT中编译: 调试IL:
离题,但太大的评论,是你也可以使用优秀的IL反汇编 有趣的是,仅在调试模式下分解IL时,Guffa的Test2 IL中还有几个额外的IL,根据Guffa的回答,这些IL在x86/x64 JIT中编译: 调试IL:
还有一件更重要的事情需要注意,不管if语句的结果如何,都将执行return。它不是if块的一部分。尝试这种微优化几乎总是被误导的——宁愿选择可读的代码,而不是假设你比编译器更聪明。如果你需要压缩性能、度量和基准,那么就没有什么灵丹妙药了。提前返回通常是一种风格上的改进,而不是与性能相关的改进,因为它减少了嵌套。请看,鉴于您的第一个代码段包含似乎是逻辑错误的内容,我想说,很明显,第二个代码段更具可读性。@Habib您是对的。那是我的打字错误,不是我项目中的错误。这里没有逻辑问题,只是性能和/或约定的问题。需要注意的另一件重要的事情是,无论if语句的结果如何,都将执行return。它不是if块的一部分。尝试这种微优化几乎总是被误导的——宁愿选择可读的代码,而不是假设你比编译器更聪明。如果你需要压缩性能、度量和基准,那么就没有什么灵丹妙药了。提前返回通常是一种风格上的改进,而不是与性能相关的改进,因为它减少了嵌套。请看,鉴于您的第一个代码段包含似乎是逻辑错误的内容,我想说,很明显,第二个代码段更具可读性。@Habib您是对的。那是我的打字错误,不是我项目中的错误。我这里没有逻辑问题,只是性能和/或惯例的问题。哇,这真的很有帮助,同时也很有趣。介意我问你如何生成这样的代码吗?我对它没有任何经验。@McAdam331:在Visual Studio中,您可以在要检查和调试的代码上设置断点。当断点命中时,打开反汇编窗口ctrl+alt+D。请注意,在调试和发布模式下编译的代码是不同的;在调试模式下,可能会添加额外的nop指令用于调试目的,并且代码没有经过优化,在发布模式下,代码可以通过优化进行重新排列,因此可能与源代码不完全相似。哇,这真的很有帮助,同时也很有趣。介意我问你如何生成这样的代码吗?我对它没有任何经验。@McAdam331:在Visual Studio中,您可以在要检查和调试的代码上设置断点。当断点命中时,打开反汇编窗口ctrl+alt+D。请注意,在调试和发布模式下编译的代码是不同的;在调试模式下,可能会添加额外的nop指令以进行调试,并且代码未经过优化,在发布模式下,可以通过优化重新排列代码,使其可能与源代码不完全相似。是否在调试模式下编译?有额外的nop指令
是的,就是这样-在LinqPad中启用optimize+会删除nops+进行其他优化。IL变得相同。您是否在调试模式下编译?当您这样做时,会添加额外的nop指令。是的,就是这样-在LinqPad中启用optimize+,nops+会删除其他优化。IL变得相同。