A friend of mine (and fellow C# coder) asked me to consider the following code:
public int ExampleMethodA()
{
while(true)
{
}
}
public int ExampleMethodB()
{
const bool loop = true;
while (loop)
{
}
}
public int ExampleMethodC()
{
bool loop = true;
while (loop)
{
}
return 0;
}
He thought it was odd that the C# compiler (.NET Framework 3.0) willingly compiles example methods A and B, but complains (as expected) on method C until you explicitly return a value.
I presented a theory that the C# compiler must optimize away the need for the return statements in example methods A and B, but not C. To dive deeper and prove my hypothesis, I dusted off trusty old ILDASM.exe and examined the MSIL generated in all three cases.
.method public hidebysig instance int32 ExampleMethodA() cil managed
{
// Code size 9 (0x9)
.maxstack 1
.locals init ([0] int32 CS$1$0000,
[1] bool CS$4$0001)
IL_0000: nop
IL_0001: br.s IL_0005
IL_0003: nop
IL_0004: nop
IL_0005: ldc.i4.1
IL_0006: stloc.1
IL_0007: br.s IL_0003
} // end of method Program::ExampleMethodA
.method public hidebysig instance int32 ExampleMethodB() cil managed
{
// Code size 9 (0x9)
.maxstack 1
.locals init ([0] int32 CS$1$0000,
[1] bool CS$4$0001)
IL_0000: nop
IL_0001: br.s IL_0005
IL_0003: nop
IL_0004: nop
IL_0005: ldc.i4.1
IL_0006: stloc.1
IL_0007: br.s IL_0003
} // end of method Program::ExampleMethodB
.method public hidebysig instance int32 ExampleMethodC() cil managed
{
// Code size 18 (0x12)
.maxstack 1
.locals init ([0] bool loop,
[1] int32 CS$1$0000,
[2] bool CS$4$0001)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: br.s IL_0007
IL_0005: nop
IL_0006: nop
IL_0007: ldloc.0
IL_0008: stloc.2
IL_0009: ldloc.2
IL_000a: brtrue.s IL_0005
IL_000c: ldc.i4.0
IL_000d: stloc.1
IL_000e: br.s IL_0010
IL_0010: ldloc.1
IL_0011: ret
} // end of method Program::ExampleMethodC
Interestingly enough, example methods A and B emit the same MSIL, and they have no RET instruction. On the other hand, example method C has slightly differing MSIL, due to a non-constant looping condition and it does have a RET instruction.
Theory confirmed: the C# compiler optimizes away the need for return statements if it can be determined the method will never actually return.
0 comments:
Post a Comment