是否有一种简单的方法可以返回带有异常的任务?

时间:2014-03-25 00:38:47

标签: c# task-parallel-library async-await

我的理解是return Task.FromResult(foo)是一个简单的简写:

var tcs = new TaskCompletionSource<TFoo>();
tcs.SetResult(foo);
return tcs.Task;

是否有一些等同于返回异常状态的任务?

var tcs = new TaskCompletionSource<TFoo>();
tcs.SetException(new NotSupportedException()); // or whatever is appropriate
return tcs.Task;

我看不到Task.FromException之类的内容。或者在不返回任务的情况下抛出异常会更合适吗?

2 个答案:

答案 0 :(得分:14)

从.NET 4.6开始,BCL中有一个Task.FromException方法。

还有Task.FromCanceled

答案 1 :(得分:12)

  

我的理解是返回Task.FromResult(foo)很简单   ... [TaskCompletionSource.SetResult]的简写。

实际上,Task.FromResult不使用TaskCompletionSourceits implementation比这简单得多。

  

是否有一些等同于返回异常状态的任务?

我认为TaskCompletionSource是最好的选择。你也可以这样做:

static Task FromExAsync(Exception ex) 
{
    var task = new Task(() => { throw ex; });
    task.RunSynchronously();
    return task;
}

在通过taskawait task进行观察之前,异常不会在返回的task.Wait()之外传播,这应该是一种理想的行为。

请注意,如果传递给FromExAsync的异常是一个活动异常(即已经被抛出并被其他地方捕获),那么重新抛出它就会丢失当前堆栈跟踪和Watson存储在异常内部的信息。有两种方法可以处理它:

  • 使用AggregateException包装例外。这将使原始例外可用AggregateException.InnerException

static Task FromExAsync(Exception ex) 
{
    var task = new Task(() => { throw new AggregateException(ex); });
    task.RunSynchronously();
    return task;
}
  • 使用ExceptionDispatchInfo.Capture来传递活动例外的状态:

static Task FromExAsync(Exception ex) 
{
    var ei = System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex);
    var task = new Task(() => { ei.Throw(); });
    task.RunSynchronously();
    return task;
}

最后,也许最简单但最差的选项(由于overhead of the state machine和编译器警告)是从async方法抛出:

static async Task FromExAsync(Exception ex)
{
    throw ex;
}