2015-02-18 21 views
7

Hãy nhìn vào mã này:Làm thế nào để chờ đợi cho đến khi công việc nội Task.ContinueWith kết thúc

private async Task InnerTask(bool outerTaskResult) 
    { 
     Console.WriteLine("2"); 
     await Task.Factory.StartNew(() => Thread.Sleep(10000)); 
     Console.WriteLine("3"); 
    } 

    private async void Button2_Click(object sender, RoutedEventArgs e) 
    { 
     var task = Task.FromResult(false); 
     Task<Task> aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result)); 
     Console.WriteLine("1"); 
     await aggregatedTask; 
     Console.WriteLine("4"); 
    } 

Kết quả mong muốn là:

1 
2 
3 
4 

Nhưng tôi nhận được:

1 
2 
4 
3 

Điều này có thể có một cái gì đó để làm với InnerTask đang được thực hiện trên một chủ đề khác nhau.

Tôi đang sử dụng ContinueWith vì các tác vụ trong mã ban đầu được tạo động và xếp hàng theo cách này.

Sử dụng phương thức .Wait() (xem bên dưới) hoạt động, nhưng tôi nghĩ đó là một ý tưởng tồi vì phương pháp đang chặn.

task.ContinueWith(task1 => InnerTask(task1.Result).Wait()) 

Cách tiếp cận chính xác ở đây là gì?

Trả lời

8

Bạn có thể sử dụng TaskExtensions.Unwrap() (mà là một phương pháp khuyến nông trên Task<Task>) để unwrap nhiệm vụ outter và lấy khu vực nội một:

private async void Button2_Click(object sender, RoutedEventArgs e) 
{ 
    var task = Task.FromResult(false); 
    Task aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result)).Unwrap(); 
    Console.WriteLine("1"); 
    await aggregatedTask; 
    Console.WriteLine("4"); 
} 

Lưu ý rằng để đơn giản hóa toàn bộ điều này, thay vì ContinueWith phong cách tiếp tục, bạn có thể await về nhiệm vụ của bạn:

private async void Button2_Click(object sender, RoutedEventArgs e) 
{ 
    var task = Task.FromResult(false); 

    Console.WriteLine("1"); 

    var result = await task; 
    await InnerTask(result); 

    Console.WriteLine("4"); 
} 
+0

'Unwrap' không thực sự cần thiết. Giá trị trả về của 'await aggregatedTask' trong câu hỏi thực sự là nhiệm vụ bên trong. –

+0

Ông có một nhiệm vụ 'Task ', đó là nhiệm vụ outter ông đang awating trên, đó là lý do tại sao nó hoàn thành * trước * outter 'Console.WriteLine'. Anh ta có thể chỉ đơn giản là "chờ đợi". –

+2

@PanagiotisKanavos Đúng, nó không * cần thiết *, người ta cũng có thể 'chờ đợi' hai lần. Cả hai sẽ làm điều tương tự. Đây chắc chắn là một cách tiếp cận phù hợp. Trong C# 5.0, bạn có thể thực sự thực hiện 'Unwrap' như:' public static async Task Unwrap (nhiệm vụ Task ) {await await task; } '(Phiên bản C# 4.0 thực sự gây khó chịu lâu dài và tẻ nhạt.) – Servy

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