您可以Ildasm.exe
在您的程序上运行以查看编译器生成的代码。我尝试过这样做,但不幸的是我的 IL 技能有点欠缺,但是您可以看到所有局部变量都被捕获为生成<Foo>d__0
类的字段。鉴于此程序:
using System;
using System.Threading.Tasks;
namespace AsyncCaptureVariables
{
class Program
{
public async Task Foo()
{
var firstName = "Karl";
var lastName = "Anderson";
var street1 = "123 Nowhere Street";
var street2 = "Apt 1-A";
var city = "Beverly Hills";
var state = "California";
var zip = "90210";
await Task.Delay(5000);
Console.WriteLine(firstName);
Console.WriteLine(city);
}
public static void Main()
{
var program = new Program();
Task t = program.Foo();
t.Wait();
}
}
}
编译器生成类似于以下部分转换为 C# 代码的内容:
using System;
class Program : System.Object
{
class <Foo>d__0 : System.ValueType, System.Runtime.CompilerServices.IAsyncStateMachine
{
public int32 <>1__state;
public System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>t__builder;
public class AsyncCaptureVariables.Program <>4__this;
public string <firstName>5__1;
public string <lastName>5__2;
public string <street1>5__3;
public string <street2>5__4;
public string <city>5__5;
public string <state>5__6;
public string <zip>5__7;
private System.Runtime.CompilerServices.TaskAwaiter <>u__$awaiter8;
private object <>t__stack;
void MoveNext()
{
try
{
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: ldfld int32 AsyncCaptureVariables.Program/'<Foo>d__0'::'<>1__state'
IL_0008: stloc.2
IL_0009: ldloc.2
IL_000a: ldc.i4.s -3
IL_000c: beq.s IL_0014
IL_000e: ldloc.2
IL_000f: ldc.i4.0
IL_0010: beq.s IL_0019
IL_0012: br.s IL_001e
IL_0014: br IL_00ee
IL_0019: br IL_00a8
IL_001e: br.s IL_0020
//000009: {
IL_0020: nop
//000010: var firstName = "Karl";
IL_0021: ldarg.0
IL_0022: ldstr "Karl"
IL_0027: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<firstName>5__1'
//000011: var lastName = "Anderson";
IL_002c: ldarg.0
IL_002d: ldstr "Anderson"
IL_0032: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<lastName>5__2'
//000012: var street1 = "123 Nowhere Street";
IL_0037: ldarg.0
IL_0038: ldstr "123 Nowhere Street"
IL_003d: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<street1>5__3'
//000013: var street2 = "Apt 1-A";
IL_0042: ldarg.0
IL_0043: ldstr "Apt 1-A"
IL_0048: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<street2>5__4'
//000014: var city = "Beverly Hills";
IL_004d: ldarg.0
IL_004e: ldstr "Beverly Hills"
IL_0053: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<city>5__5'
//000015: var state = "California";
IL_0058: ldarg.0
IL_0059: ldstr "California"
IL_005e: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<state>5__6'
//000016: var zip = "90210";
IL_0063: ldarg.0
IL_0064: ldstr "90210"
IL_0069: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<zip>5__7'
//000017:
//000018: await Task.Delay(5000);
IL_006e: ldc.i4 0x1388
IL_0073: call class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Threading.Tasks.Task::Delay(int32)
IL_0078: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter [mscorlib]System.Threading.Tasks.Task::GetAwaiter()
IL_007d: stloc.3
IL_0078: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter [mscorlib]System.Threading.Tasks.Task::GetAwaiter()
IL_007d: stloc.3
IL_007e: ldloca.s CS$0$0001
IL_0080: call instance bool [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::get_IsCompleted()
IL_0085: brtrue.s IL_00c6
IL_0087: ldarg.0
IL_0088: ldc.i4.0
IL_0089: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
IL_008e: ldarg.0
IL_008f: ldloc.3
IL_0090: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter AsyncCaptureVariables.Program/<Foo>d__0::<>u__$awaiter8
IL_0095: ldarg.0
IL_0096: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_009b: ldloca.s CS$0$0001
IL_009d: ldarg.0
IL_009e: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter,valuetype AsyncCaptureVariables.Program/<Foo>d__0>(!!0&,
!!1&)
IL_00a3: nop
IL_00a4: ldc.i4.0
IL_00a5: stloc.0
IL_00a6: leave.s IL_011d
IL_00a8: ldarg.0
IL_00a9: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter AsyncCaptureVariables.Program/<Foo>d__0::<>u__$awaiter8
IL_00ae: stloc.3
IL_00af: ldarg.0
IL_00b0: ldloca.s CS$0$0002
IL_00b2: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter
IL_00b8: ldloc.s CS$0$0002
IL_00ba: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter AsyncCaptureVariables.Program/<Foo>d__0::<>u__$awaiter8
IL_00bf: ldarg.0
IL_00c0: ldc.i4.m1
IL_00c1: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
IL_00c6: ldloca.s CS$0$0001
IL_00c8: call instance void [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::GetResult()
IL_00cd: nop
IL_00ce: ldloca.s CS$0$0001
IL_00d0: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter
//000019:
//000020: Console.WriteLine(firstName);
IL_00d6: ldarg.0
IL_00d7: ldfld string AsyncCaptureVariables.Program/<Foo>d__0::<firstName>5__1
IL_00dc: call void [mscorlib]System.Console::WriteLine(string)
IL_00e1: nop
//000021: Console.WriteLine(city);
IL_00e2: ldarg.0
IL_00e3: ldfld string AsyncCaptureVariables.Program/<Foo>d__0::<city>5__5
IL_00e8: call void [mscorlib]System.Console::WriteLine(string)
IL_00ed: nop
//000022: }
//000023:
//000024: public static void Main()
//000025: {
//000026: var program = new Program();
//000027: Task t = program.Foo();
//000028: t.Wait();
//000029: }
//000030: }
//000031: }
IL_00ee: leave.s IL_0108
} // end .try
catch [mscorlib]System.Exception
{
IL_00f0: stloc.1
IL_00f1: ldarg.0
IL_00f2: ldc.i4.s -2
IL_00f4: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
IL_00f9: ldarg.0
IL_00fa: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_00ff: ldloc.1
IL_0100: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetException(class [mscorlib]System.Exception)
IL_0105: nop
IL_0106: leave.s IL_011d
} // end handler
IL_0108: nop
//000022: }
IL_0109: ldarg.0
IL_010a: ldc.i4.s -2
IL_010c: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
//000023:
//000024: public static void Main()
//000025: {
//000026: var program = new Program();
//000027: Task t = program.Foo();
//000028: t.Wait();
//000029: }
//000030: }
//000031: }
IL_0111: ldarg.0
IL_0112: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_0117: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetResult()
IL_011c: nop
IL_011d: nop
IL_011e: ret
} // end of method <Foo>d__0::MoveNext
.method private hidebysig newslot virtual final
instance void SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine param0) cil managed
{
.custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 )
.override [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_0006: ldarg.1
IL_0007: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine)
IL_000c: ret
} // end of method <Foo>d__0::SetStateMachine
} // end of class <Foo>d__0