2016-02-04 69 views
4

考虑下面的代码片段获取例外:异步等待来自内部任务结果

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
r.Result无法访问。

更新

var r = Task.WhenAny(tasks).Result; // produces exactly the same wrapped result! 

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

enter image description here

+2

不确定这是否相关,但是'Task.Factory.StartNew'不支持'async'委托。改为使用'Task.Run'。 –

+2

另外,你为什么要创建一个新的任务来调用像“CheckActivityTimeout”这样的异步方法?为什么不直接打给他们呢? –

+0

更改代码以使用'Task.Run'具有相同的结果。 – Jim

回答

6

你的问题,是因为如何Task.WhenAny作品。 Task.WhenAny返回任务,其结果是完成的任务。这就是为什么read.Result是一个任务,而这又是一个例外。

这不是真的清楚什么所需语义,但如果你想StartReading表面首先完成的任务的结果,你可以使用“双重的await”,像这样:

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

在附注中,请勿使用StartNew。如果您需要移除UI线程的CPU绑定(或其他阻止代码),请使用Task.Run;否则,只需直接调用方法即可。

+0

所以'等待Task.WhenAny(阅读,activityCheck);'是最后投票的答案,嗯?我原以为应该只有一个“等待” - 就像我的答案一样。 –

+0

@DavidPine:'await await'观察内部任务异常。也就是说,内部的'await'会先完成任何任务(这个'await'永远不会失败);那么外部的“await”观察该任务的结果,传播任何异常。 –

+0

感谢分享!我今天学到了一些东西......虽然有点难看。 –

-1

我发现另一个解决问题的办法就是将结果转换为Task<Task>

铸造的Task.WhenAny结果也将获得内的任务。

var result = Task.WhenAny(reading, activityCheck).Result; 
var inner = ((Task<Task>)result).Result; 
inner.Exception... 
+0

堆栈溢出不应该允许downvotes没有评论,这工作得很好。 – Jim