我一直在想:臭名昭著的VB。NET语句"On Error Resume Next"转换为CIL?它是否包括用try…catch来包装每一行?
返回。
不能在一个方法中结合try-catch和遗留错误处理。当您使用On Error Resume Next
时,方法中的每一行代码都获得一个标签以及唯一标识符。在伪c#代码中:
int currentId = 0;
Label1:
currentId = 1;
Line1();
Label2:
currentId = 2;
Line2();
Label3:
currentId = 3;
Line3();
Exit:
整个方法被封装在try catch中。当异常发生时,catch处理程序将检查currentId
并对行中的下一个标签执行简单的goto
(并且设置了ProjectError
)。在我们的例子中,它看起来像这样:
try
{
...
}
catch (Exception ex)
{
ProjectData.SetProjectError(ex);
if (currentId == 1) goto Label2;
if (currentId == 2) goto Label3;
if (currentId == 3) goto Exit;
}
请注意,这只是我通过反编译VB得到的实现细节。网络应用程序。唯一的合同行为是On Error Resume Next
中定义的,基本上可以归结为"设置项目错误并继续下一个语句"。
给你:
Public Sub A()
End Sub
Public Sub B()
End Sub
Public Sub C()
End Sub
Public Sub D()
End Sub
Public Sub E()
End Sub
Public Sub Test()
A()
On Error GoTo ErrorHandler
B()
Exit Sub
C()
ErrorHandler:
D()
Resume Next
E()
End Sub
编译为(不含补充方法):
.method public static void Test() cil managed
{
// Code size 201 (0xc9)
.maxstack 3
.locals init (int32 V_0,
int32 V_1,
int32 V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.2
IL_0002: call void VBTest.Program::A()
IL_0007: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
IL_000c: ldc.i4.2
IL_000d: stloc.0
IL_000e: ldc.i4.3
IL_000f: stloc.2
IL_0010: call void VBTest.Program::B()
IL_0015: leave IL_00c0
IL_001a: ldc.i4.5
IL_001b: stloc.2
IL_001c: call void VBTest.Program::C()
IL_0021: ldc.i4.6
IL_0022: stloc.2
IL_0023: call void VBTest.Program::D()
IL_0028: ldc.i4.7
IL_0029: stloc.2
IL_002a: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
IL_002f: ldloc.1
IL_0030: brtrue.s IL_0047
IL_0032: ldc.i4 0x800a0014
IL_0037: call class [mscorlib]System.Exception [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::CreateProjectError(int32)
IL_003c: throw
IL_003d: ldc.i4.s 9
IL_003f: stloc.2
IL_0040: call void VBTest.Program::E()
IL_0045: leave.s IL_00c0
IL_0047: ldloc.1
IL_0048: ldc.i4.1
IL_0049: add
IL_004a: ldc.i4.0
IL_004b: stloc.1
IL_004c: switch (
IL_007d,
IL_0000,
IL_0007,
IL_000e,
IL_0015,
IL_001a,
IL_0021,
IL_0028,
IL_003d,
IL_003d,
IL_0045)
IL_007d: leave.s IL_00b5
IL_007f: ldloc.2
IL_0080: stloc.1
IL_0081: ldloc.0
IL_0082: switch (
IL_0093,
IL_0047,
IL_0021)
IL_0093: leave.s IL_00b5
IL_0095: isinst [mscorlib]System.Exception
IL_009a: ldnull
IL_009b: cgt.un
IL_009d: ldloc.0
IL_009e: ldc.i4.0
IL_009f: cgt.un
IL_00a1: and
IL_00a2: ldloc.1
IL_00a3: ldc.i4.0
IL_00a4: ceq
IL_00a6: and
IL_00a7: endfilter
IL_00a9: castclass [mscorlib]System.Exception
IL_00ae: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception)
IL_00b3: leave.s IL_007f
IL_00b5: ldc.i4 0x800a0033
.try IL_0000 to IL_0095 filter IL_0095 handler IL_00a9 to IL_00b5
IL_00ba: call class [mscorlib]System.Exception [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::CreateProjectError(int32)
IL_00bf: throw
IL_00c0: ldloc.1
IL_00c1: brfalse.s IL_00c8
IL_00c3: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
IL_00c8: ret
} // end of method Program::Test
这个像差被Reflector反编译为:
public static void Test()
{
int num2;
try
{
int num3;
Label_0000:
num3 = 1;
A();
Label_0007:
ProjectData.ClearProjectError();
int num = 2;
Label_000E:
num3 = 3;
B();
goto Label_00C0;
Label_001A:
num3 = 5;
C();
Label_0021:
num3 = 6;
D();
Label_0028:
num3 = 7;
ProjectData.ClearProjectError();
if (num2 != 0)
{
goto Label_0047;
}
throw ProjectData.CreateProjectError(-2146828268);
Label_003D:
num3 = 9;
E();
goto Label_00C0;
Label_0047:
num2 = 0;
switch ((num2 + 1))
{
case 1:
goto Label_0000;
case 2:
goto Label_0007;
case 3:
goto Label_000E;
case 4:
case 10:
goto Label_00C0;
case 5:
goto Label_001A;
case 6:
goto Label_0021;
case 7:
goto Label_0028;
case 8:
case 9:
goto Label_003D;
default:
goto Label_00B5;
}
Label_007F:
num2 = num3;
switch (num)
{
case 0:
goto Label_00B5;
case 1:
goto Label_0047;
case 2:
goto Label_0021;
}
}
catch (object obj1) when (?)
{
ProjectData.SetProjectError((Exception) obj1);
goto Label_007F;
}
Label_00B5:
throw ProjectData.CreateProjectError(-2146828237);
Label_00C0:
if (num2 != 0)
{
ProjectData.ClearProjectError();
}
}
除了它使用了一堆开关和goto之外,我不知道这段代码实际做了什么。