C# 试图理解任务。继续使用()

C# 试图理解任务。继续使用(),c#,C#,我试图理解(在我眼里)一些奇怪的行为。我调用了某个异步方法,希望检索其结果。(DeleteIndexAsync返回一个任务) 在此场景中,结果为假,状态为等待激活 而这个代码就是我想要的 var deleteTask = Task.Run(() => DeleteIndexAsync(localItem)); deleteTask.ContinueWith(t => { //handle and log exceptions return false

我试图理解(在我眼里)一些奇怪的行为。我调用了某个异步方法,希望检索其结果。(
DeleteIndexAsync
返回一个
任务

在此场景中,
结果
状态
等待激活

而这个代码就是我想要的

  var deleteTask = Task.Run(() => DeleteIndexAsync(localItem));
  deleteTask.ContinueWith(t =>
   {
     //handle and log exceptions
     return false;
   }, TaskContinuationOptions.OnlyOnFaulted);

  if (!deleteTask.Result)
有人能解释一下原因吗?这里是否可以使用
异步
/
等待
而不是
任务

编辑:


如果像第一个示例中那样链接调用,则分配给
deleteTask
变量的值实际上是第二个
Task
。这是一个仅在第一个任务失败时运行的任务(调用
DeleteIndexAsync

这是因为
Task.Run
Task.ContinueWith
返回它们创建的
Task
s。它解释了为什么在第一个示例中,您会得到
状态==WaitingForActivation
。在第一个代码段中,访问
deleteTask.Result
将引发异常。如果抛出了
DeleteIndexAsync
,则它将是一个包含原始异常的
AggregateException
(除非您访问了
t.exception
),否则它将声明“操作已取消”-这是因为您试图获得按条件安排的任务的结果,但该条件未满足

如果您创建的方法包含截断的
async
,您可以这样做(未测试):

关于问题编辑:

使用捕获的变量应该会有所帮助,但您当前的解决方案引入了竞争条件。在这种情况下,最好这样做:

var deleteTask = Task.Run(() => ThrowEx());    

try
{
    deleteTask.Wait();
} 
catch (Exception ex)
{
    return true;
}

但此时您可以完全放弃异步调用,因为您会立即等待结果-除非本示例简化了
Run
wait
之间可以完成的工作)

如果您链接调用,如第一个示例中所示,分配给
deleteTask
变量的值实际上是第二个
Task
。这是一个仅在第一个任务失败时运行的任务(调用
DeleteIndexAsync

这是因为
Task.Run
Task.ContinueWith
返回它们创建的
Task
s。它解释了为什么在第一个示例中,您会得到
状态==WaitingForActivation
。在第一个代码段中,访问
deleteTask.Result
将引发异常。如果抛出了
DeleteIndexAsync
,则它将是一个包含原始异常的
AggregateException
(除非您访问了
t.exception
),否则它将声明“操作已取消”-这是因为您试图获得按条件安排的任务的结果,但该条件未满足

如果您创建的方法包含截断的
async
,您可以这样做(未测试):

关于问题编辑:

使用捕获的变量应该会有所帮助,但您当前的解决方案引入了竞争条件。在这种情况下,最好这样做:

var deleteTask = Task.Run(() => ThrowEx());    

try
{
    deleteTask.Wait();
} 
catch (Exception ex)
{
    return true;
}
但此时您可以完全放弃异步调用,因为您会立即等待结果-除非本例简化了
Run
wait
之间可以完成的工作

我调用了某个异步方法,希望检索其结果

有人能解释一下原因吗

在第一个示例中,
deleteTask
是从
task.Run
返回的任务。在第二个示例中,
deleteTask
是从
ContinueWith
返回的任务。除非
DeleteIndexAsync
引发异常,否则此任务不会实际执行

这里是否可以使用async/await代替Task

是的,那是最好的办法。在使用异步代码时,您应该始终使用。在这种情况下,
TaskContinuationOptions.OnlyOnFaulted
意味着您应该在
wait
之后将继续代码放入
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)
  ...
我调用了某个异步方法,希望检索其结果

有人能解释一下原因吗

在第一个示例中,
deleteTask
是从
task.Run
返回的任务。在第二个示例中,
deleteTask
是从
ContinueWith
返回的任务。除非
DeleteIndexAsync
引发异常,否则此任务不会实际执行

这里是否可以使用async/await代替Task

是的,那是最好的办法。在使用异步代码时,您应该始终使用。在这种情况下,
TaskContinuationOptions.OnlyOnFaulted
意味着您应该在
wait
之后将继续代码放入
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)
  ...

我认为检查task.Result以确定是否发生错误也不是一个好主意?正在访问任务。结果在此处引发异常。。。而且Faulted标志始终为false,即使抛出异常时也是如此。@user3292642我想我不明白?您应该访问
Exception
属性来接受异常。我不想接受异常。我已经在用continuewith方法记录它了。日志记录完成后,如果抛出异常,我想返回,但我不知道如何返回。我想检查状态也不是一个选项。你能检查我的编辑吗?局部变量会起作用吗?或者是编译器在我的支票b上运行