2016-10-15 29 views
2

私はいつも不思議だった:悪名高いVB.NETステートメント "On Error Resume Next"はどのようにCILに変換されたのですか?それはtry ... catchesですべての行を折り返しますか?オンエラー再開のCIL実装

答えて

3

後藤。

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でラップされます。例外がヒットした場合、キャッチハンドラは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.NETアプリケーションによって得ただけで、実装の詳細は次のとおりです。私たちの場合は、次のようになります。唯一の契約上の動作は、On Error Resume Nextで定義されたものです。これは、基本的に「プロジェクトエラーを設定して次のステートメントに進む」ことです。

0

ここに行く:

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 

このabberationはこれに反射して逆コンパイルされます:脇から

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(); 
    } 
} 

実際にはたくさんのスイッチやヒートポンを使用していることから、そのコードが実際に何をしているのかわかりません。

関連する問題