我试图了解一些(在我看来)奇怪的行为。我调用了一些异步方法,并希望检索其结果。 (DeleteIndexAsync
返回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;
}
答案 0 :(得分:2)
如果您将调用链接起来,就像在第一个示例中一样,您分配给deleteTask
变量的值实际上是第二个Task
。这是应该仅在第一个任务失败时运行的那个(调用DeleteIndexAsync
的那个)。
这是因为Task.Run
和Task.ContinueWith
都返回了他们创建的Task
。它解释了为什么在第一个例子中你得到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
之间可以完成的工作)
答案 1 :(得分:2)
我调用了一些异步方法,并希望检索其结果。
The best way to do this is with await
, not Result
有人可以解释原因吗?
在第一个示例中,deleteTask
是从Task.Run
返回的任务。在第二个示例中,deleteTask
是从ContinueWith
返回的任务。除非DeleteIndexAsync
抛出异常,否则此任务实际上永远不会执行。
是否可以在此处使用async / await而不是Task?
是的,这是最好的方法。使用异步代码时,您应始终use await
instead of ContinueWith
。在这种情况下,TaskContinuationOptions.OnlyOnFaulted
表示您应该将延续代码放在catch
之后的await
块中:
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)
...