2015-05-14 14 views
5

Tôi có một số mã tôi hạ cấp từ .NET 4.5's đáng yêu asyncawait từ khóa để .NET 4.0. Tôi đang sử dụng ContinueWith để tạo sự tiếp tục tương tự như cách hoạt động của await.Làm thế nào để nắm bắt một OperationCanceledException khi sử dụng ContinueWith

Về cơ bản, mã cũ của tôi là:

var tokenSource = newCancellationTokenSource(); 
var myTask = Task.Run(() => 
{ 
    return MyStaticClass.DoStuff(tokenSource.Token); 
}, tokenSource.Token); 
try 
{ 
    var result = await myTask; 
    DoStuffWith(result); 
} 
catch (OperationCanceledException) 
{ 
    // Cancel gracefully. 
} 

(Như người ta có thể mong đợi, MyStaticClass.DoStuff(token) thường xuyên gọi token.ThrowIfCancellationRequested().)

mã mới của tôi trông như thế này:

var tokenSource = new CancellationTokenSource(); 
try 
{ 
    Task.Factory.StartNew(() => 
    { 
     return MyStaticClass.DoStuff(tokenSource.Token); 
    }, tokenSource.Token) 
    .ContinueWith(task => 
    { 
     var param = new object[1]; 
     param[0] = task.Result; 
     // I need to use Invoke here because "DoStuffWith()" does UI stuff. 
     Invoke(new MyDelegate(DoStuffWith, param)); 
    }); 
} 
catch (OperationCanceledException) 
{ 
    // Cancel gracefully. 
} 

Tuy nhiên, OperationCanceledException không bao giờ bị bắt. Chuyện gì vậy? Tôi đặt khối try/catch ở đâu?

+5

Lưu ý rằng bạn có thể sử dụng chờ đợi với .NET 4.0 sử dụng https://www.nuget.org/packages/Microsoft.Bcl.Async/ –

Trả lời

6

Việc hủy được xử lý khác với các trường hợp ngoại lệ khác. Về cơ bản, bạn có thể sử dụng mô hình này:

Task.Factory.StartNew(() => 
{ 
    // The task 
}, tokenSource.Token) 
.ContinueWith(task => 
{ 
    // The normal stuff 
}, TaskContinuationOptions.OnlyOnRanToCompletion) 
.ContinueWith(task => 
{ 
    // Handle cancellation 
}, TaskContinuationOptions.OnlyOnCanceled) 
.ContinueWith(task => 
{ 
    // Handle other exceptions 
}, TaskContinuationOptions.OnlyOnFaulted); 

Hoặc thay thế một:

Task.Factory.StartNew(() => 
{ 
    // The task 
}, tokenSource.Token) 
.ContinueWith(task => 
{ 
    switch (task.Status) 
    { 
    case TaskStatus.RanToCompletion: 
     // The normal stuff 
     break; 
    case TaskStatus.Canceled: 
     // Handle cancellation 
     break; 
    case TaskStatus.Faulted: 
     // Handle other exceptions 
     break; 
    } 
}); 

Trong trường hợp của bạn, bạn không bắt bất cứ điều gì bởi vì:

  • Task.Factory.StartNew lợi nhuận ngay lập tức và luôn thành công.
  • tiếp nối của bạn luôn chạy
  • Truy cập task.Result ném một AggregateException kể từ khi nhiệm vụ bị hủy
  • Trường hợp ngoại lệ không được xử lý bởi bất cứ điều gì kể từ khi nó được ném từ một thread hồ bơi. Rất tiếc. Chuyện gì xảy ra tiếp theo depends on the framework version:

    • Trong .NET < 4.5, quá trình này sẽ được chấm dứt ngay sau khi nhiệm vụ không được hoàn thiện, kể từ khi bạn có một ngoại lệ không quan sát được.
    • Trong .NET> = 4.5, ngoại lệ sẽ tự động bị xóa.
Các vấn đề liên quan