async await从内部任务结果中获取异常

时间:2016-02-04 12:34:36

标签: c# async-await

给出以下代码段:

public Task StartReading()
{
  var activityCheck = Task.Factory.StartNew(async () => await this.CheckActivityTimeout(), this._token.Token).Unwrap();
  var reading = Task.Factory.StartNew(async () => await this.ReadAsync(), this._token.Token).Unwrap();

  // for reference, this code produces the same result:
  // var activityCheck = this.CheckActivityTimeout();
  // var reading = this.ReadAsync();

  return Task.WhenAny(reading, activityCheck);
}

CheckActivityTimeout中抛出异常时,我会按如下方式捕获它。

var read = StartReading()
var tasks = new Task[] { read, taskx, tasky, taskz };
int completed = Task.WaitAny(tasks);
var r = tasks[completed];

r没有设置异常。相反,如果我查看调试器,我发现任务r将异常存储在Result属性中。我如何得到这个实际结果?

r的类型为Id = 17, Status = RanToCompletion, Method = "{null}", Result = "System.Threading.Tasks.UnwrapPromise``1[System.Threading.Tasks.TaskExtensions+VoidResult]"

您可以看到实际异常位于内部任务的结果中。我如何向上传播?

r.Exception == null
<{1}}无法访问。

更新

r.Result

在调试器中它看起来像这样:

enter image description here

2 个答案:

答案 0 :(得分:6)

您的问题是因为Task.WhenAny的工作原理。 Task.WhenAny返回任务,其结果是已完成的任务。这就是read.Result是一个任务的原因,而这个任务又包含异常。

不太清楚所需的语义是什么,但是如果你希望StartReading显示第一个完成任务的结果,你可以使用&#34 ;等待&#34;,像这样:

public async Task StartReadingAsync()
{
  var activityCheck = this.CheckActivityTimeout();
  var reading = this.ReadAsync();
  await await Task.WhenAny(reading, activityCheck);
}

在旁注中,请勿使用StartNew。如果你需要移出UI线程的CPU绑定(或其他阻塞代码),那么使用Task.Run;否则,只需直接调用方法。

答案 1 :(得分:-1)

我发现该问题的另一个解决方案就是将结果转换为data.table

投射Task<Task>的结果也将获得内部任务。

Task.WhenAny