给出以下代码段:
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
在调试器中它看起来像这样:
答案 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