试图理解Task.ContinueWith()
本文关键字:ContinueWith Task | 更新日期: 2023-09-27 18:08:32
我试图理解一些(在我看来)奇怪的行为。我有一个调用一些异步方法,并希望检索其结果。(DeleteIndexAsync
return a Task<bool>
)
var deleteTask = Task.Run(() => DeleteIndexAsync(localItem))
.ContinueWith(t =>
{
//handle and log exceptions
}, TaskContinuationOptions.OnlyOnFaulted);
if (!deleteTask.Result)
本场景中Result
为false
, Status
为WaitingForActivation
。
而这段代码做了我想要的
var deleteTask = Task.Run(() => DeleteIndexAsync(localItem));
deleteTask.ContinueWith(t =>
{
//handle and log exceptions
return false;
}, TaskContinuationOptions.OnlyOnFaulted);
if (!deleteTask.Result)
有人能解释一下吗?这里是否可以使用async
/await
代替Task
?
var deleteTask = Task.Run(() => ThrowEx());
bool errorOccurred = false;
deleteTask.ContinueWith(t =>
{
errorOccurred = true;
}, TaskContinuationOptions.OnlyOnFaulted);
if (errorOccurred)
{
return true;
}
如果您链接调用,如在第一个示例中,您分配给deleteTask
变量的值实际上是第二个Task
。它应该只在第一个任务(调用DeleteIndexAsync
的任务)失败时运行。
这是因为Task.Run
和Task.ContinueWith
都返回它们创建的Task
s。它解释了为什么在第一个示例中得到Status == WaitingForActivation
。在第一个代码片段中,访问deleteTask.Result
将导致抛出异常。如果DeleteIndexAsync
抛出,它将是包含原始异常的AggregateException
(除非您访问了t.Exception
),否则它将声明"操作被取消"-这是因为您试图获得有条件调度的任务的结果,并且不满足条件。
如果你的方法包含剪辑的async
,你可以这样做(未测试):
bool success = false;
try
{
success = await DeleteIndexAsync(localItem);
}
catch (Exception) {}
if (!success)
{
//TODO: handler
}
关于问题编辑:
使用捕获的变量应该会有所帮助,但是您当前的解决方案引入了竞争条件。在这种情况下,最好这样做:
var deleteTask = Task.Run(() => ThrowEx());
try
{
deleteTask.Wait();
}
catch (Exception ex)
{
return true;
}
,但是此时您可以完全放弃异步调用,因为您将立即等待结果(除非本示例简化了可以在Run
和Wait
之间完成的工作)
我有一个异步方法的调用,想要检索它的结果。
最好的方法是使用await
,而不是Result
。
有人能解释一下吗?
在第一个示例中,deleteTask
是Task.Run
返回的任务。在第二个示例中,deleteTask
是从ContinueWith
返回的任务。除非DeleteIndexAsync
抛出异常,否则此任务永远不会实际执行。
是否可以在这里使用async/await而不是Task ?
是的,这是最好的方法。在处理异步代码时,应该始终使用await
而不是ContinueWith
。在本例中,TaskContinuationOptions.OnlyOnFaulted
意味着您应该将延续代码放在await
之后的catch
块中:
bool deleteResult;
try
{
deleteResult = await Task.Run(() => DeleteIndexAsync(localItem));
}
catch (Exception ex)
{
//handle and log exceptions
}
if (!deleteResult)
...
或者,因为DeleteIndexAsync
看起来是异步的,删除Task.Run
会更合适:
bool deleteResult;
try
{
deleteResult = await DeleteIndexAsync(localItem);
}
catch (Exception ex)
{
//handle and log exceptions
}
if (!deleteResult)
...