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