此 C# 代码:
private void LoadAssignments(AssignmentType assignmentType, Collection<Assignment> assignments)
{
bool flag;
DataTable lessons = this.GetResults(assignmentType);
try
{
IEnumerator enumerator = lessons.Rows.GetEnumerator();
try
{
while (true)
{
flag = enumerator.MoveNext();
if (!flag)
{
break;
}
DataRow row = (DataRow)enumerator.Current;
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
flag = disposable == null;
if (!flag)
{
disposable.Dispose();
}
}
}
finally
{
flag = lessons == null;
if (!flag)
{
lessons.Dispose();
}
}
}
生成此 CIL (.NET 4)
.method private hidebysig
instance void LoadAssignments (
valuetype TTReporterCore.AssignmentType assignmentType,
class [mscorlib]System.Collections.ObjectModel.Collection`1<valuetype TTReporterCore.Assignment> assignments
) cil managed
{
.locals init (
[0] bool flag,
[1] class [System.Data]System.Data.DataTable lessons,
[2] class [mscorlib]System.Collections.IEnumerator enumerator,
[3] class [System.Data]System.Data.DataRow row,
[4] class [mscorlib]System.IDisposable disposable,
[5] bool flag1
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call instance class [System.Data]System.Data.DataTable TTReporterCore.TTReader::GetResults(valuetype TTReporterCore.AssignmentType)
IL_0008: stloc.1
.try
{
IL_0009: nop
IL_000a: ldloc.1
IL_000b: callvirt instance class [System.Data]System.Data.DataRowCollection [System.Data]System.Data.DataTable::get_Rows()
IL_0010: callvirt instance class [mscorlib]System.Collections.IEnumerator [System.Data]System.Data.InternalDataCollectionBase::GetEnumerator()
IL_0015: stloc.2
.try
{
IL_0016: nop
IL_0017: br.s IL_0038
.loop
{
IL_0019: nop
IL_001a: ldloc.2
IL_001b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: stloc.s flag1
IL_0024: ldloc.s flag1
IL_0026: brtrue.s IL_002b
IL_0028: nop
IL_0029: br.s IL_003d
IL_002b: ldloc.2
IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0031: castclass [System.Data]System.Data.DataRow
IL_0036: stloc.3
IL_0037: nop
IL_0038: ldc.i4.1
IL_0039: stloc.s flag1
IL_003b: br.s IL_0019
}
IL_003d: nop
IL_003e: leave.s IL_0062
}
finally
{
IL_0040: nop
IL_0041: ldloc.2
IL_0042: isinst [mscorlib]System.IDisposable
IL_0047: stloc.s disposable
IL_0049: ldloc.s disposable
IL_004b: ldnull
IL_004c: ceq
IL_004e: stloc.0
IL_004f: ldloc.0
IL_0050: stloc.s flag1
IL_0052: ldloc.s flag1
IL_0054: brtrue.s IL_0060
IL_0056: nop
IL_0057: ldloc.s disposable
IL_0059: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005e: nop
IL_005f: nop
IL_0060: nop
IL_0061: endfinally
}
IL_0062: nop
IL_0063: nop
IL_0064: leave.s IL_007e
}
finally
{
IL_0066: nop
IL_0067: ldloc.1
IL_0068: ldnull
IL_0069: ceq
IL_006b: stloc.0
IL_006c: ldloc.0
IL_006d: stloc.s flag1
IL_006f: ldloc.s flag1
IL_0071: brtrue.s IL_007c
IL_0073: nop
IL_0074: ldloc.1
IL_0075: callvirt instance void [System]System.ComponentModel.MarshalByValueComponent::Dispose()
IL_007a: nop
IL_007b: nop
IL_007c: nop
IL_007d: endfinally
}
IL_007e: nop
IL_007f: ret
}
为什么MSIL要添加flag1,继续执行相同的逻辑设置flag,将flag1设置为flag,最后检查!flag1。 对我来说,这似乎是编译器效率低下的原因。
更新:我使用的是 Telerik 的 JustDecompile,虽然结果与 ILDASM 有很大不同,但额外的布尔值仍然是在调试模式下创建的。
此外,我修改了代码,完全删除了布尔值,调试版本仍然添加了布尔值。 我真的在寻找编译器为什么这样做。
似乎创建了一个临时本地来保存比较结果(即disposable == null)。
尝试这个例子:
class Program
{
static void Main()
{
if (1 == 1) return;
}
}
..在我的机器上生成以下 IL(Microsoft (R) Visual C# 2010 编译器版本 4.0.30319.1):
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ret
}
本地 V_0 已创建,尽管实际上并未使用它。我相信即使对于“非”优化编译来说,这也是一个明显的优化:)..或更可能的是:生成所有必要的代码以启用调试。我不知道它如何在调试会话中使用,但这是我最好的猜测。
编译时优化(即发布配置)我没有看到额外的本地。
当我编写类似的程序时,额外的变量在释放模式下没有出现。 在汇编视图中相同,调试显示正在设置额外的变量([ebp-44h]),而发布则没有:
调试:
发布: