11

观察任务内抛出的异常有多种方式。其中之一是与OnlyOnFaulted一个ContinueWith:在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?

+1

你是什么意思的观察?您的ContinueWith委托只会被调用一次,如果这就是您的意思,无论您是否访问该异常对象。 – 2012-07-31 15:40:37

+0

也许他的意思是“如果我简单地调用'OnlyOnFaulted'而不管访问't.Exceptions'”是否会重新抛出异常? – user7116 2012-07-31 15:45:25

+0

如果您不“观察”任务引发的异常(这是Microsoft术语),那么垃圾收集器将在稍后为您抛出它们。我的ContinueWith委托肯定会被多次调用(如果在我的主任务中有多个任务会抛出异常),或者它可以用带有所有抛出的异常的AggregateException树调用? – davenewza 2012-07-31 15:47:18

回答

10

他们被视为观察到一旦您访问Exception属性。请参阅AggregateException.Handle。您可以使用t.Exception.Handle代替:

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

谢谢。似乎有很多方法来处理任务异常。 – davenewza 2012-07-31 16:04:24

+1

是的,我更喜欢Handle方法;因为它更加明确。但是,在任何情况下都可能无法使用。 – 2012-07-31 16:07:25

2

样品

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

如果要将异常标记为已处理(如上面的回答),那么传递给Handle()函数的谓词不应该返回true吗?我想这取决于你想要做什么,但我在这里假设我们要将异常标记为已处理。 – 2013-09-25 22:05:38