2013-08-15 33 views
10

Trong phương thức async, mọi biến cục bộ đều được lưu trữ sao cho khi chuỗi bất kỳ tiếp tục sau khi await sẽ có quyền truy cập vào các giá trị. Có cách nào để chỉ ra giá trị nào thực sự cần thiết sau await không?Tôi có thể chỉ định biến nào tôi muốn tồn tại sau khi hoàn thành việc chờ tiếp tục không?

Ví dụ:

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

Console.WriteLine(firstName); 
Console.WriteLine(city); 

Vì vậy, tôi đã tuyên bố 7 biến địa phương, nhưng chỉ sử dụng 2 trong số họ sau khi await, là có bất kỳ thuộc tính Tôi có thể trang trí các biến của tôi với để cho biết rằng tôi có ý định chỉ sử dụng firstNamecity sau khi hoàn tất await? Lưu ý: Đây là một ví dụ giả tạo, nhưng có vẻ như nó có thể có lợi để có thể hạn chế lưu trữ các khối dữ liệu lớn nếu chúng không cần thiết khi chuỗi tiếp theo kết thúc công việc.

+0

Tôi nghĩ rằng điều này là tốt hơn trái để trình biên dịch. – Diryboy

Trả lời

6

Không, bạn không thể. (Khác với các giải pháp rõ ràng của việc chia chúng thành các phương pháp riêng biệt hoặc đặt chúng thành null).

Trình biên dịch không được tối ưu hóa hoàn toàn trong trường hợp này; nó có thể nắm bắt nhiều biến hơn nhu cầu và có thể giữ chúng lâu hơn mức cần thiết. Đây có lẽ là điều mà Microsoft sẽ tối ưu trong tương lai.

+0

Có thể họ sẽ giải quyết nó trong C# 6, sẽ chờ xem. :-) –

0

Bạn có thể tạo phạm vi bằng cách thêm dấu ngoặc trong mã, nhưng bất cứ khi nào một cái gì đó không được tham chiếu nữa trình biên dịch sẽ thu thập rằng anyways. làm điều này

{ //start of scope 
    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 MyTaskHere(); 
}//end of scope 

Có những thứ khác có thể được xem xét như thể bạn có thể tạo phương pháp phân chia lôgic một cách logic theo ý kiến ​​của tôi là một lựa chọn tốt hơn. Mặc dù không có hại gì khi làm theo cách này.

+0

Nó không rõ ràng với tôi như thế nào thêm một phạm vi sẽ có bất kỳ tác dụng. –

+0

Việc thêm phạm vi không gây ra bất kỳ điều gì được đặt thành rỗng. Người dân địa phương thậm chí không thực sự là người dân địa phương nữa. Chúng được chuyển đổi thành các trường trên trình biên dịch tạo ra việc thực thi 'IAsyncStateMachine'. –

+0

Cho phép gọi theo cách này, vì các biến sẽ nằm ngoài phạm vi sau khi đóng khung vì vậy chúng sẽ tốt cho GC được thu thập. – Ehsan

3

Bạn có thể chạy Ildasm.exe trên chương trình của mình để xem trình biên dịch tạo mã nào. Tôi đã cố gắng để làm điều này nhưng tiếc là kỹ năng IL của tôi là một chút thiếu, tuy nhiên bạn có thể thấy rằng tất cả các biến địa phương được chụp như là các lĩnh vực của lớp <Foo>d__0 tạo ra. Với chương trình này:

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

Trình biên dịch tạo ra một cái gì đó giống như sau một phần chuyển đổi sang mã 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 
+0

+1 để biết chi tiết về những gì đang diễn ra đằng sau hậu trường, không nhận ra một máy trạng thái được sử dụng để lưu trữ các giá trị. –

Các vấn đề liên quan