我试图测试一个我可以取消任务的场景,以及如果先前任务没有完成则应该继续运行的延续。代码示例如下:
static void Main(string[] args)
{
var source = new CancellationTokenSource();
var task = Task.Factory.StartNew(() =>
{
while (true)
{
source.Token.ThrowIfCancellationRequested();
}
}, source.Token);
var continuation = task.ContinueWith(t =>
{
Console.WriteLine("Continuation");
if (t.Status == TaskStatus.Faulted)
{
Console.WriteLine("Antecedent Faulted: " + t.Exception.Message);
}
}, source.Token, TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.AttachedToParent, TaskScheduler.Current);
var cancellation = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
source.Cancel();
});
try
{
continuation.Wait();
}
catch (AggregateException)
{
Console.WriteLine("AggregateException");
}
Console.WriteLine("Done");
while (!Console.KeyAvailable) { }
}
该程序的输出是:
AggregateException
Done
在某种程度上,我明白了。主要任务被取消,最终抛出一个TaskCanceledException,它被包装在AggregateException中。问题是,这是预期的行为吗?如果是这样,TaskStatus.Faulted在延续中有什么用,如果该延续没有被执行?我甚至设置了一个循环检查ConsoleKeyAvailable,以防止继续运行以及抛出AggregateException。
答案 0 :(得分:1)
我认为发生这种情况的原因是您将source.Token
作为CancellationToken
传递给task.ContinueWith
。尽管将NotOnRanToCompletion
作为延续选项传递,但在继续任务开始之前取消令牌的事实意味着调度程序可以立即将其转换为已取消状态而不实际运行它。