我只是想进入IL,因为我正在使用代码注入。我需要分析代码并涵盖各种情况。
遗憾的是,如果最后一条指令在if子句中,那么最后注入一个方法调用并不起作用,因为那时调用包含了该调用。
现在我一直在分析if-code被翻译成IL并且我对如何完成这一点感到有些困惑。显然编译器会反转if。这是出于性能原因吗?如果是这样,这会改善表现吗?
亲眼看看:
string test;
Random rnd = new Random();
bool b = rnd.Next(0, 10) == 3;
if (b)
{
// TRUE
test = "True branch";
// END TRUE
}
else
{
// FALSE
test = "False branch";
//END FALSE
}
这是输出:
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.Random::.ctor()
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: ldc.i4.0
IL_0009: ldc.i4.s 10
IL_000b: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32)
IL_0010: ldc.i4.3
IL_0011: ceq
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3
IL_001a: brtrue.s IL_0026
IL_001c: nop
IL_001d: ldstr "True branch"
IL_0022: stloc.0
IL_0023: nop
IL_0024: br.s IL_002e
IL_0026: nop
IL_0027: ldstr "False branch"
IL_002c: stloc.0
IL_002d: nop
IL_002e: ret
正如您所看到的,在将Random结果与const 3进行比较之后,它再次与0进行比较,从而反转结果,相当于if (false)
。
这是什么原因?由于您需要额外的说明,它的性能是否较差?这总是发生吗?
答案 0 :(得分:1)
您正在查看调试版本。将其更改为发布版本,并使用brfalse.s
IL_0000: newobj instance void [mscorlib]System.Random::.ctor()
IL_0005: stloc.1
IL_0006: ldloc.1
IL_0007: ldc.i4.0
IL_0008: ldc.i4.s 10
IL_000a: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32)
IL_000f: ldc.i4.3
IL_0010: ceq
IL_0012: stloc.2
IL_0013: ldloc.2
IL_0014: brfalse.s IL_001e
IL_0016: ldstr "True branch"
IL_001b: stloc.0
IL_001c: br.s IL_0024
IL_001e: ldstr "False branch"
IL_0023: stloc.0
我添加了Console.WriteLine
,否则删除了test
变量。
IL_0024: ldloc.0
IL_0025: call void [mscorlib]System.Console::WriteLine(string)
IL_002a: ret
所以Debug和release之间的区别是:
// Debug
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3
IL_001a: brtrue.s IL_0026
VS
// Release
IL_0014: brfalse.s IL_001e
所以有四个关于Debug版本的附加指令,以及一个" inverse"如果
首先我要说C#编译器试图保持代码的顺序与它的编写顺序相同。首先," true"分支,那么"假"分支。
好的......我做了一个假设......
让我们说问题是在调试模式下......在调试模式下,代码必须是详细的...非常详细。所以
if (b)
被翻译为
if (b == true)
遗憾的是true
是"什么 - 但是0",所以写起来更容易
if (!(b == false))
因为false
是" 0"。但这是在调试模式下编写的:-)只有调试模式使用临时变量
as
// bool temp = b == false;
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3
和
// if (temp) // go to else branch
IL_001a: brtrue.s IL_0026
答案 1 :(得分:0)
编译器没有反转任何东西。请注意,if
语句的两个分支在IL中的顺序与源代码中的顺序相同。你可以从两个字符串的顺序看到。
当布尔值为false时,brtrue
的使用只是分支的自然IL。测试真值的布尔值意味着将它与0进行比较。值0为假,其他任何东西都被认为是真的。
因此,编译器发出IL以与0进行比较。如果该比较为真,即如果布尔值的序数值为0,则布尔值为false。因此,如果等于零,则这是你所拥有的,如果布尔值为假,则表示分支。这是ceq
对0,然后是brtrue
。
那就是说,值得指出的是,编译调试性能不是问题。编译器希望编写代码以使调试器可以检查变量。如果您对性能感兴趣,则必须从发布版本中查看IL。当你这样做时,你会看到完全不同的代码。