0

我试图了解使用async-时创建的状态机await。我采用了一段简单的 C# 代码

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

并使用 Roslyn 获得反编译的 IL

.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()方法的工作原理。我假设这是检查底层操作是否完成的地方。有人可以将其翻译成伪代码吗?

4

1 回答 1

0

MoveNext只是意味着“运行此方法的下一部分”。它有一个“状态”,告诉它方法停止的地方。有关详细信息,请参阅Jon Skeet 的博客

于 2016-12-18T00:07:43.840 回答