2016-12-13 33 views
-1

我想了解使用async - await時創建的狀態機。我把一件簡單的C#代碼就僞代碼而言,MIL中的IAsyncStateMachine中的MoveNext有什麼作用?

using System; 
using System.Net; 
using System.Threading.Tasks; 
public class C 
{ 
    public static async Task<string> GetGoogleDotComHtml() 
    { 
     using(WebClient wc = new WebClient()) 
     { 
      var task = new Task<string>(() => wc.DownloadString("http://google.com")); 
      string html = await task; 
      return html; 
     } 
    } 
    public void M() 
    { 
     string googleHomepage = GetGoogleDotComHtml().Result; 
     Console.WriteLine(googleHomepage); 
    } 
} 

,並使用羅斯林獲得的

.class private auto ansi '<Module>' 
{ 
} // end of class <Module> 

.class public auto ansi beforefieldinit C 
    extends [mscorlib]System.Object 
{ 
    // Nested Types 
    .class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_0' 
     extends [mscorlib]System.Object 
    { 
     .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
      01 00 00 00 
     ) 
     // Fields 
     .field public class [System]System.Net.WebClient wc 

     // Methods 
     .method public hidebysig specialname rtspecialname 
      instance void .ctor() cil managed 
     { 
      // Method begins at RVA 0x20b0 
      // Code size 8 (0x8) 
      .maxstack 8 

      IL_0000: ldarg.0    // Load argument 0 onto the stack 
      IL_0001: call instance void [mscorlib]System.Object::.ctor() // Call method indicated on the stack with arguments 
      IL_0006: nop     // Do nothing (No operation) 
      IL_0007: ret     // Return from method, possibly with a value 
     } // end of method '<>c__DisplayClass0_0'::.ctor 

     .method assembly hidebysig 
      instance string '<GetGoogleDotComHtml>b__0'() cil managed 
     { 
      // Method begins at RVA 0x20b9 
      // Code size 17 (0x11) 
      .maxstack 8 

      IL_0000: ldarg.0    // Load argument 0 onto the stack 
      IL_0001: ldfld class [System]System.Net.WebClient C/'<>c__DisplayClass0_0'::wc // Push the value of field of object (or value type) obj, onto the stack 
      IL_0006: ldstr "http://google.com" // Push a string object for the literal string 
      IL_000b: callvirt instance string [System]System.Net.WebClient::DownloadString(string) // Call a method associated with an object 
      IL_0010: ret     // Return from method, possibly with a value 
     } // end of method '<>c__DisplayClass0_0'::'<GetGoogleDotComHtml>b__0' 

    } // end of class <>c__DisplayClass0_0 

    .class nested private auto ansi sealed beforefieldinit '<GetGoogleDotComHtml>d__0' 
     extends [mscorlib]System.Object 
     implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine 
    { 
     .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
      01 00 00 00 
     ) 
     // Fields 
     .field public int32 '<>1__state' 
     .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> '<>t__builder' 
     .field private class C/'<>c__DisplayClass0_0' '<>8__1' 
     .field private class [mscorlib]System.Threading.Tasks.Task`1<string> '<task>5__2' 
     .field private string '<html>5__3' 
     .field private string '<>s__4' 
     .field private valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string> '<>u__1' 

     // Methods 
     .method public hidebysig specialname rtspecialname 
      instance void .ctor() cil managed 
     { 
      // Method begins at RVA 0x20b0 
      // Code size 8 (0x8) 
      .maxstack 8 

      IL_0000: ldarg.0    // Load argument 0 onto the stack 
      IL_0001: call instance void [mscorlib]System.Object::.ctor() // Call method indicated on the stack with arguments 
      IL_0006: nop     // Do nothing (No operation) 
      IL_0007: ret     // Return from method, possibly with a value 
     } // end of method '<GetGoogleDotComHtml>d__0'::.ctor 

     .method private final hidebysig newslot virtual 
      instance void MoveNext() cil managed 
     { 
      .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() 
      // Method begins at RVA 0x20cc 
      // Code size 302 (0x12e) 
      .maxstack 3 
      .locals init (
       [0] int32, 
       [1] string, 
       [2] valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string>, 
       [3] string, 
       [4] class C/'<GetGoogleDotComHtml>d__0', 
       [5] class [mscorlib]System.Exception 
      ) 

      IL_0000: ldarg.0    // Load argument 0 onto the stack 
      IL_0001: ldfld int32 C/'<GetGoogleDotComHtml>d__0'::'<>1__state' // Push the value of field of object (or value type) obj, onto the stack 
      IL_0006: stloc.0    // Pop a value from stack into local variable 0 
      IL_0007: ldloc.0    // Load local variable 0 onto stack 
      IL_0008: brfalse.s IL_000c // Branch to target if value is zero (false), short form 
      IL_000a: br.s IL_000e   // Branch to target, short form 
      IL_000c: br.s IL_002a   // Branch to target, short form 
      IL_000e: nop     // Do nothing (No operation) 
      IL_000f: ldarg.0    // Load argument 0 onto the stack 
      IL_0010: newobj instance void C/'<>c__DisplayClass0_0'::.ctor() // Allocate an uninitialized object or value type and call ctor 
      IL_0015: stfld class C/'<>c__DisplayClass0_0' C/'<GetGoogleDotComHtml>d__0'::'<>8__1' // Replace the value of field of the object obj with value 
      IL_001a: ldarg.0    // Load argument 0 onto the stack 
      IL_001b: ldfld class C/'<>c__DisplayClass0_0' C/'<GetGoogleDotComHtml>d__0'::'<>8__1' // Push the value of field of object (or value type) obj, onto the stack 
      IL_0020: newobj instance void [System]System.Net.WebClient::.ctor() // Allocate an uninitialized object or value type and call ctor 
      IL_0025: stfld class [System]System.Net.WebClient C/'<>c__DisplayClass0_0'::wc // Replace the value of field of the object obj with value 
      IL_002a: nop     // Do nothing (No operation) 
      IL_002b: ldloc.0    // Load local variable 0 onto stack 
      IL_002c: brfalse.s IL_0030 // Branch to target if value is zero (false), short form 
      IL_002e: br.s IL_0032   // Branch to target, short form 
      IL_0030: br.s IL_008c   // Branch to target, short form 
      IL_0032: nop     // Do nothing (No operation) 
      IL_0033: ldarg.0    // Load argument 0 onto the stack 
      IL_0034: ldarg.0    // Load argument 0 onto the stack 
      IL_0035: ldfld class C/'<>c__DisplayClass0_0' C/'<GetGoogleDotComHtml>d__0'::'<>8__1' // Push the value of field of object (or value type) obj, onto the stack 
      IL_003a: ldftn instance string C/'<>c__DisplayClass0_0'::'<GetGoogleDotComHtml>b__0'() // Push a pointer to a method referenced by method, on the stack 
      IL_0040: newobj instance void class [mscorlib]System.Func`1<string>::.ctor(object, native int) // Allocate an uninitialized object or value type and call ctor 
      IL_0045: newobj instance void class [mscorlib]System.Threading.Tasks.Task`1<string>::.ctor(class [mscorlib]System.Func`1<!0>) // Allocate an uninitialized object or value type and call ctor 
      IL_004a: stfld class [mscorlib]System.Threading.Tasks.Task`1<string> C/'<GetGoogleDotComHtml>d__0'::'<task>5__2' // Replace the value of field of the object obj with value 
      IL_004f: ldarg.0    // Load argument 0 onto the stack 
      IL_0050: ldfld class [mscorlib]System.Threading.Tasks.Task`1<string> C/'<GetGoogleDotComHtml>d__0'::'<task>5__2' // Push the value of field of object (or value type) obj, onto the stack 
      IL_0055: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<!0> class [mscorlib]System.Threading.Tasks.Task`1<string>::GetAwaiter() // Call a method associated with an object 
      IL_005a: stloc.2    // Pop a value from stack into local variable 2 
      IL_005b: ldloca.s 2   // Load address of local variable with index indx, short form 
      IL_005d: call instance bool valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string>::get_IsCompleted() // Call method indicated on the stack with arguments 
      IL_0062: brtrue.s IL_00a8  // Branch to target if value is non-zero (true), short form 
      IL_0064: ldarg.0    // Load argument 0 onto the stack 
      IL_0065: ldc.i4.0    // Push 0 onto the stack as int32 
      IL_0066: dup     // Duplicate the value on the top of the stack 
      IL_0067: stloc.0    // Pop a value from stack into local variable 0 
      IL_0068: stfld int32 C/'<GetGoogleDotComHtml>d__0'::'<>1__state' // Replace the value of field of the object obj with value 
      IL_006d: ldarg.0    // Load argument 0 onto the stack 
      IL_006e: ldloc.2    // Load local variable 2 onto stack 
      IL_006f: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>u__1' // Replace the value of field of the object obj with value 
      IL_0074: ldarg.0    // Load argument 0 onto the stack 
      IL_0075: stloc.s 4   // Pop a value from stack into local variable indx, short form 
      IL_0077: ldarg.0    // Load argument 0 onto the stack 
      IL_0078: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>t__builder' // Push the address of field of object obj on the stack 
      IL_007d: ldloca.s 2   // Load address of local variable with index indx, short form 
      IL_007f: ldloca.s 4   // Load address of local variable with index indx, short form 
      IL_0081: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string>, class C/'<GetGoogleDotComHtml>d__0'>(!!0&, !!1&) // Call method indicated on the stack with arguments 
      IL_0086: nop     // Do nothing (No operation) 
      IL_0087: leave IL_012d  // Exit a protected region of code 
      IL_008c: ldarg.0    // Load argument 0 onto the stack 
      IL_008d: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>u__1' // Push the value of field of object (or value type) obj, onto the stack 
      IL_0092: stloc.2    // Pop a value from stack into local variable 2 
      IL_0093: ldarg.0    // Load argument 0 onto the stack 
      IL_0094: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>u__1' // Push the address of field of object obj on the stack 
      IL_0099: initobj valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string> // Initialize the value at address dest 
      IL_009f: ldarg.0    // Load argument 0 onto the stack 
      IL_00a0: ldc.i4.m1   // Push -1 onto the stack as int32 
      IL_00a1: dup     // Duplicate the value on the top of the stack 
      IL_00a2: stloc.0    // Pop a value from stack into local variable 0 
      IL_00a3: stfld int32 C/'<GetGoogleDotComHtml>d__0'::'<>1__state' // Replace the value of field of the object obj with value 
      IL_00a8: ldloca.s 2   // Load address of local variable with index indx, short form 
      IL_00aa: call instance !0 valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string>::GetResult() // Call method indicated on the stack with arguments 
      IL_00af: stloc.3    // Pop a value from stack into local variable 3 
      IL_00b0: ldloca.s 2   // Load address of local variable with index indx, short form 
      IL_00b2: initobj valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<string> // Initialize the value at address dest 
      IL_00b8: ldarg.0    // Load argument 0 onto the stack 
      IL_00b9: ldloc.3    // Load local variable 3 onto stack 
      IL_00ba: stfld string C/'<GetGoogleDotComHtml>d__0'::'<>s__4' // Replace the value of field of the object obj with value 
      IL_00bf: ldarg.0    // Load argument 0 onto the stack 
      IL_00c0: ldarg.0    // Load argument 0 onto the stack 
      IL_00c1: ldfld string C/'<GetGoogleDotComHtml>d__0'::'<>s__4' // Push the value of field of object (or value type) obj, onto the stack 
      IL_00c6: stfld string C/'<GetGoogleDotComHtml>d__0'::'<html>5__3' // Replace the value of field of the object obj with value 
      IL_00cb: ldarg.0    // Load argument 0 onto the stack 
      IL_00cc: ldnull    // Push a null reference on the stack 
      IL_00cd: stfld string C/'<GetGoogleDotComHtml>d__0'::'<>s__4' // Replace the value of field of the object obj with value 
      IL_00d2: ldarg.0    // Load argument 0 onto the stack 
      IL_00d3: ldfld string C/'<GetGoogleDotComHtml>d__0'::'<html>5__3' // Push the value of field of object (or value type) obj, onto the stack 
      IL_00d8: stloc.1    // Pop a value from stack into local variable 1 
      IL_00d9: leave.s IL_0118  // Exit a protected region of code, short form 
      IL_00db: ldloc.0    // Load local variable 0 onto stack 
      IL_00dc: ldc.i4.0    // Push 0 onto the stack as int32 
      IL_00dd: bge.s IL_00fd  // Branch to target if greater than or equal to, short form 
      IL_00df: ldarg.0    // Load argument 0 onto the stack 
      IL_00e0: ldfld class C/'<>c__DisplayClass0_0' C/'<GetGoogleDotComHtml>d__0'::'<>8__1' // Push the value of field of object (or value type) obj, onto the stack 
      IL_00e5: ldfld class [System]System.Net.WebClient C/'<>c__DisplayClass0_0'::wc // Push the value of field of object (or value type) obj, onto the stack 
      IL_00ea: brfalse.s IL_00fd // Branch to target if value is zero (false), short form 
      IL_00ec: ldarg.0    // Load argument 0 onto the stack 
      IL_00ed: ldfld class C/'<>c__DisplayClass0_0' C/'<GetGoogleDotComHtml>d__0'::'<>8__1' // Push the value of field of object (or value type) obj, onto the stack 
      IL_00f2: ldfld class [System]System.Net.WebClient C/'<>c__DisplayClass0_0'::wc // Push the value of field of object (or value type) obj, onto the stack 
      IL_00f7: callvirt instance void [mscorlib]System.IDisposable::Dispose() // Call a method associated with an object 
      IL_00fc: nop     // Do nothing (No operation) 
      IL_00fd: endfinally   // End finally clause of an exception block 
      IL_00fe: stloc.s 5   // Pop a value from stack into local variable indx, short form 
      IL_0100: ldarg.0    // Load argument 0 onto the stack 
      IL_0101: ldc.i4.s -2   // Push num onto the stack as int32, short form 
      IL_0103: stfld int32 C/'<GetGoogleDotComHtml>d__0'::'<>1__state' // Replace the value of field of the object obj with value 
      IL_0108: ldarg.0    // Load argument 0 onto the stack 
      IL_0109: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>t__builder' // Push the address of field of object obj on the stack 
      IL_010e: ldloc.s 5   // Load local variable of index indx onto stack, short form 
      IL_0110: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetException(class [mscorlib]System.Exception) // Call method indicated on the stack with arguments 
      IL_0115: nop     // Do nothing (No operation) 
      IL_0116: leave.s IL_012d  // Exit a protected region of code, short form 
      IL_0118: ldarg.0    // Load argument 0 onto the stack 
      IL_0119: ldc.i4.s -2   // Push num onto the stack as int32, short form 
      IL_011b: stfld int32 C/'<GetGoogleDotComHtml>d__0'::'<>1__state' // Replace the value of field of the object obj with value 
      IL_0120: ldarg.0    // Load argument 0 onto the stack 
      IL_0121: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>t__builder' // Push the address of field of object obj on the stack 
      IL_0126: ldloc.1    // Load local variable 1 onto stack 
      IL_0127: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::SetResult(!0) // Call method indicated on the stack with arguments 
      IL_012c: nop     // Do nothing (No operation) 
      IL_012d: ret     // Return from method, possibly with a value 

      Try IL_002b-IL_00db Finally IL_00db-IL_00fe 
      Try IL_0007-IL_00fe Catch class [mscorlib]System.Exception IL_00fe-IL_0118 
     } // end of method '<GetGoogleDotComHtml>d__0'::MoveNext 

     .method private final hidebysig newslot virtual 
      instance void SetStateMachine (
       class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine 
      ) cil managed 
     { 
      .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = (
       01 00 00 00 
      ) 
      .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) 
      // Method begins at RVA 0x2224 
      // Code size 1 (0x1) 
      .maxstack 8 

      IL_0000: ret     // Return from method, possibly with a value 
     } // end of method '<GetGoogleDotComHtml>d__0'::SetStateMachine 

    } // end of class <GetGoogleDotComHtml>d__0 


    // Methods 
    .method public hidebysig static 
     class [mscorlib]System.Threading.Tasks.Task`1<string> GetGoogleDotComHtml() cil managed 
    { 
     .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = (
      01 00 1b 43 2b 3c 47 65 74 47 6f 6f 67 6c 65 44 
      6f 74 43 6f 6d 48 74 6d 6c 3e 64 5f 5f 30 00 00 
     ) 
     .custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = (
      01 00 00 00 
     ) 
     // Method begins at RVA 0x2050 
     // Code size 52 (0x34) 
     .maxstack 2 
     .locals init (
      [0] class C/'<GetGoogleDotComHtml>d__0', 
      [1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> 
     ) 

     IL_0000: newobj instance void C/'<GetGoogleDotComHtml>d__0'::.ctor() // Allocate an uninitialized object or value type and call ctor 
     IL_0005: stloc.0    // Pop a value from stack into local variable 0 
     IL_0006: ldloc.0    // Load local variable 0 onto stack 
     IL_0007: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Create() // Call method indicated on the stack with arguments 
     IL_000c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>t__builder' // Replace the value of field of the object obj with value 
     IL_0011: ldloc.0    // Load local variable 0 onto stack 
     IL_0012: ldc.i4.m1   // Push -1 onto the stack as int32 
     IL_0013: stfld int32 C/'<GetGoogleDotComHtml>d__0'::'<>1__state' // Replace the value of field of the object obj with value 
     IL_0018: ldloc.0    // Load local variable 0 onto stack 
     IL_0019: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>t__builder' // Push the value of field of object (or value type) obj, onto the stack 
     IL_001e: stloc.1    // Pop a value from stack into local variable 1 
     IL_001f: ldloca.s 1   // Load address of local variable with index indx, short form 
     IL_0021: ldloca.s 0   // Load address of local variable with index indx, short form 
     IL_0023: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::Start<class C/'<GetGoogleDotComHtml>d__0'>(!!0&) // Call method indicated on the stack with arguments 
     IL_0028: ldloc.0    // Load local variable 0 onto stack 
     IL_0029: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string> C/'<GetGoogleDotComHtml>d__0'::'<>t__builder' // Push the address of field of object obj on the stack 
     IL_002e: call instance class [mscorlib]System.Threading.Tasks.Task`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<string>::get_Task() // Call method indicated on the stack with arguments 
     IL_0033: ret     // Return from method, possibly with a value 
    } // end of method C::GetGoogleDotComHtml 

    .method public hidebysig 
     instance void M() cil managed 
    { 
     // Method begins at RVA 0x2090 
     // Code size 20 (0x14) 
     .maxstack 1 
     .locals init (
      [0] string 
     ) 

     IL_0000: nop     // Do nothing (No operation) 
     IL_0001: call class [mscorlib]System.Threading.Tasks.Task`1<string> C::GetGoogleDotComHtml() // Call method indicated on the stack with arguments 
     IL_0006: callvirt instance !0 class [mscorlib]System.Threading.Tasks.Task`1<string>::get_Result() // Call a method associated with an object 
     IL_000b: stloc.0    // Pop a value from stack into local variable 0 
     IL_000c: ldloc.0    // Load local variable 0 onto stack 
     IL_000d: call void [mscorlib]System.Console::WriteLine(string) // Call method indicated on the stack with arguments 
     IL_0012: nop     // Do nothing (No operation) 
     IL_0013: ret     // Return from method, possibly with a value 
    } // end of method C::M 

    .method public hidebysig specialname rtspecialname 
     instance void .ctor() cil managed 
    { 
     // Method begins at RVA 0x20b0 
     // Code size 8 (0x8) 
     .maxstack 8 

     IL_0000: ldarg.0    // Load argument 0 onto the stack 
     IL_0001: call instance void [mscorlib]System.Object::.ctor() // Call method indicated on the stack with arguments 
     IL_0006: nop     // Do nothing (No operation) 
     IL_0007: ret     // Return from method, possibly with a value 
    } // end of method C::.ctor 

} // end of class C 

我想了解的是MoveNext()方法是如何工作的反編譯IL。我認爲這是檢查完成的地方,看看底層操作是否完成。有人可以將它翻譯成僞代碼嗎?

+2

爲什麼不反編譯爲C#而不是IL? – ColinM

回答

0

MoveNext只是意味着「運行此方法的下一部分」。它有一個「狀態」,告訴它方法停止的地方。有關更多信息,請參見Jon Skeet's blog