问题 在ContinueWith中观察任务异常


有多种方法可以观察任务中抛出的异常。其中一个是在带有OnlyOnFaulted的ContinueWith中:

var task = Task.Factory.StartNew(() =>
{
    // Throws an exception 
    // (possibly from within another task spawned from within this task)
});

var failureTask = task.ContinueWith((t) =>
{
    // Flatten and loop (since there could have been multiple tasks)
    foreach (var ex in t.Exception.Flatten().InnerExceptions)
        Console.WriteLine(ex.Message);
}, TaskContinuationOptions.OnlyOnFaulted);

我的问题:一旦failureTask开始,是否会自动观察异常,或者只有在我触摸'ex.Message时才会被观察到异常?


1596
2017-07-31 15:34


起源

观察是什么意思?无论您是否访问异常对象,您的ContinueWith委托只会被调用一次,如果这是您的意思。 - Chris Shain
也许他的意思是“如果我只是打电话,它会重新抛出异常 OnlyOnFaulted 无论访问 t.Exceptions“? - user7116
如果您没有“观察”从Tasks抛出的异常(这是Microsoft术语),那么垃圾收集器将在稍后为您抛出它们。我的ContinueWith委托肯定可以被多次调用(如果我的主任务中的多个任务抛出异常)......或者它可以用带有所有抛出异常的AggregateException树调用? - davenewza
“只是调度t1的延续是不足以观察它的异常......你需要以某种方式实际查看异常,或者通过等待它来抛出异常,或者在之后访问它的异常属性任务出现故障,等等。“好的,所以我实际上需要查看Exception来观察它。资源: social.msdn.microsoft.com/Forums/en-US/parallelextensions/... - davenewza


答案:


他们被视为 观察到的 一旦你访问了 Exception 属性。

也可以看看 AggregateException.Handle。您可以使用 t.Exception.Handle 代替:

t.Exception.Handle(exception =>
            {
            Console.WriteLine(exception);
            return true;
            }
    );

10
2017-07-31 15:52



谢谢。似乎有很多方法可以处理任务异常。 - davenewza
是的,我更喜欢Handle方法;因为它更明确。但是,它可能无法在所有情况下使用。 - Peter Ritchie


样品

Task.Factory.StartNew(testMethod).ContinueWith(p =>
            {
                if (p.Exception != null)
                    p.Exception.Handle(x =>
                        {
                            Console.WriteLine(x.Message);
                            return false;
                        });
            });

2
2018-06-04 14:47



传递给Handle()函数的谓词不应该返回true,如果你想将异常标记为已处理(如上面的上一个答案)?我想这取决于你想做什么,但我想在这里我们想要将异常标记为已处理。 - Hugh Robinson