使用ContinueWith时如何捕获OperationCanceledException [英] How to catch an OperationCanceledException when using ContinueWith
问题描述
我有一些代码将从.NET 4.5的可爱的async
和await
关键字降级为.NET 4.0.我正在使用ContinueWith
创建类似于await
工作方式的延续.
I have some code I'm downgrading from .NET 4.5's lovely async
and await
keywords to .NET 4.0. I'm using ContinueWith
to create a continuation similar to the way await
works.
基本上,我的旧代码是:
Basically, my old code was:
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.
}
(如人们所料,MyStaticClass.DoStuff(token)
会定期调用token.ThrowIfCancellationRequested()
.)
(As one might expect, MyStaticClass.DoStuff(token)
regularly calls token.ThrowIfCancellationRequested()
.)
我的新代码如下:
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.
}
但是,OperationCanceledException
从未被捕获.这是怎么回事?我在哪里放置try/catch块?
However, the OperationCanceledException
is never caught. What's going on? Where do I put my try/catch block?
推荐答案
取消处理的方式与其他异常不同.基本上,您可以使用以下模式:
Cancellation is handled differently from other exceptions. Basically, you can use this pattern:
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);
或另一种选择:
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;
}
});
在您的情况下,您没有捕获任何东西,因为:
In your case, you're not catching anything because:
-
Task.Factory.StartNew
立即返回并且始终成功. - 您的延续总是运行的
- 访问
task.Result
会自任务以来抛出AggregateException
被取消
Task.Factory.StartNew
returns immediately and always succeeds.- Your continuation always runs
- Accessing
task.Result
throws anAggregateException
since the task is canceled The exception is not handled by anything since it's thrown from a thread pool thread. Oops. What happens next depends on the framework version:
- 在.NET中< 4.5,由于您有一个未观察到的异常,一旦失败的任务完成,该过程将立即终止.
- 在.NET> = 4.5中,该异常将被静默删除.
这篇关于使用ContinueWith时如何捕获OperationCanceledException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!