抓住任务抛出异常

时间:2013-12-11 20:42:13

标签: c# .net task-parallel-library

TaskScheduler ts= TaskScheduler.FromCurrentSynchronizationContext();
try
{
    Task<T> task1 = ...
    task1.ContinueWith(t =>
    {
        ...
        Task<T> task2 = ...
        task2.ContinueWith(u =>
        {
            ...
            Task<T> task3 = ...
            task3.ContinueWith(w =>
            {
                ...
            }, new CancellationToken(), TaskContinuationOptions.OnlyOnRanToCompletion, ts);
        }, new CancellationToken(), TaskContinuationOptions.OnlyOnRanToCompletion, ts);
    }, new CancellationToken(), TaskContinuationOptions.OnlyOnRanToCompletion, ts);
} 
catch(Exception)
{
    MessageBox.Show("...");
}      

您好。我有一些代码(如上所述)。这对我不起作用。我有三个任务在服务器端工作但修改UI,因此所有这些任务都应该在UI线程中生成。更重要的是:如果第二个完成失败,第三个任务不能运行,第二个任务无法运行,除非第一个成功完成。因此,如果第一个以失败告终,我的任务树应该抛出异常并打破其余的操作。如何以最简单的方式实现这一目标?

更新

现在我的代码看起来像

private async void SomeMethod()
{
 ...
 try
 {
      var r1 = await Method1(...);
      var r2 = await Method2(...);
  var r3 = await Method3(...);
 }
 catch
 {
      MessageBox.Show("..."); 
 }
}

private Task<...> Method1(...)
{
  Task<...> task = Task<...>.Factory.StartNew(() =>
  {
         ...
         try
         {
               // Result is null (but that's ok) so 'index out of range exception' is thrown
               // It calls my method MyException with this exception (but I don't know in 
               // which thread and how to catch this (shouldn't be catch by async SomeMethod?)
               result = ....Results[0];
         }
         catch (Exception ex)
         {
               MyException(ex);
         }
    return result;
    });
    return task;
}

public void MyException(Exception ex)
{
  throw ex;
}

但我仍然无法捕捉异常。

修改 解决了。我没有捕获异常(只在Method1中忽略)和:

var r1 = await Method1(...);
if(r1!=null)
{
    var r2 = await Method2(...);
    var r3 = await Method3(...);
}
else
{
    ...do sth instead of catching ex
}

1 个答案:

答案 0 :(得分:4)

最简单的选择是在这里使用await,因为它将提供您想要的错误处理语义,只需要很少的努力;允许您编写代码,就像它是常规同步代码一样:

try
{
    var firstResult = await SomethingAsync();
    var secondResult = await SomethingElseAsync(firstResult);
    var finalResult = await AnotherThingAsync(secondResult);
}
catch
{
    //handle an exception thrown by any of the above async operations.
}

如果你不能这样做(由于在.NET 4.0上),那么你可以使用here描述的Then方法来获得你想要的语义:

var finalTask = SomethingAsync()
.Then(firstResult => SomethingElseAsync(firstResult))
.Then(secondResult => AnotherThingAsync(secondResult));

finalTask.ContinueWith(t => HandleError(t.Exception),
    TaskContinuationOptions.OnlyOnFaulted);

Then本质上是对ContinueWith的调用,但具有不同的错误处理语义。如果正在继续的任务抛出异常,则Then只传播该异常,而不是运行延续。 ContinueWith只运行延续并吞下异常。