如果没有等待异步任务在哪里抛出异常? [英] Where does an async Task throw Exception if it is not awaited?

查看:28
本文介绍了如果没有等待异步任务在哪里抛出异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的例子:(也请阅读代码中的注释,因为它会更有意义)

public async Task>MyAsyncMethod(){任务<结果>resultTask = await _mySender.PostAsync();返回结果任务;//在现实生活中,这将返回到另一个我无法更改的程序集//但我需要对这里的 Result 做一些异常处理}

让我们假设 _mySenderPostAsync 方法如下所示:

public Task>PostAsync(){任务<结果>结果 = GetSomeTask();返回结果;}

问题是:

因为我不等待 MyAsyncMethod 中的实际 Result 并且如果 PostAsync 方法抛出异常,则上下文是异常会被抛出和处理吗?

有什么方法可以处理程序集中的异常?

当我尝试将 MyAsyncMethod 更改为:

时,我感到很惊讶

 public async Task>MyAsyncMethod(){尝试{任务<结果>resultTask = await _mySender.PostAsync();返回结果任务;}捕获(MyCustomException 前){}}

这里捕获了异常,如果没有等待实际结果,则发生事件.碰巧 PostAsync 的结果已经可用,在这个上下文中抛出异常对吧??

是否可以使用 ContinueWith 来处理当前类中的异常?例如:

public async Task>MyAsyncMethod(){任务<结果>resultTask = await _mySender.PostAsync();var exceptionHandlingTask = resultTask.ContinueWith(t => { handle(t.Exception)}, TaskContinuationOptions.OnlyOnFaulted);返回结果任务;}

解决方案

这是很多问题要打包成一个问题",但还好...

<块引用>

如果没有等待异步任务在哪里抛出异常?

未观察到的任务异常由 TaskScheduler.UnobservedTaskException 事件引发.此事件最终"引发,因为在其异常被视为未处理之前,任务实际上必须被垃圾收集.

<块引用>

由于我不等待 MyAsyncMethod 中的实际结果,并且如果 PostAsync 方法抛出异常,那么将在哪个上下文中抛出和处理异常?

任何使用 async 修饰符并返回 Task 的方法都会将其所有异常放在返回的 Task 上.

<块引用>

有什么方法可以处理程序集中的异常?

是的,您可以替换返回的任务,例如:

异步任务<结果>HandleExceptionsAsync(Task original){尝试{返回等待原件;}抓住 ...}公共异步任务<任务<结果>>MyAsyncMethod(){任务<结果>resultTask = await _mySender.PostAsync();返回 HandleExceptionsAsync(resultTask);}

<块引用>

令我惊讶的是,当我尝试将 MyAsyncMethod 更改为 [同步返回内部任务] 时,这里捕获了异常,即使没有等待实际结果.

这实际上意味着您调用的方法不是 async Task,如您的代码示例所示.这是一个非asyncTask 返回的方法,当这些方法之一抛出异常时,它会像任何其他异常一样被处理(即,它直接向上传递调用堆栈;它没有放在返回的 Task 上).

<块引用>

是否可以使用ContinueWith来处理当前类中的异常?

是的,但是await 更简洁.

I have the following example: (please also read comments in code, as it will make more sense )

public async Task<Task<Result>> MyAsyncMethod() 
{
    Task<Result> resultTask = await _mySender.PostAsync();
    return resultTask; 

    // in real-life case this returns to a different assembly which I can't change
   // but I need to do some exception handling on the Result in here
}

let's assume the PostAsync method of _mySender looks like this:

public Task<Task<Result>> PostAsync() 
{
  Task<Result> result = GetSomeTask(); 
  return result;
}

The question is:

As I don't await for the actual Result in the MyAsyncMethod and if PostAsync method throws an exception, in which context is the exception going to be thrown and handled?

and

Is there any way I can handle exceptions in my assembly?

I was surprised that when I tried to change MyAsyncMethod to:

 public async Task<Task<Result>> MyAsyncMethod() 
{
  try 
  {
    Task<Result> resultTask = await _mySender.PostAsync();
    return resultTask; 
  }
  catch (MyCustomException ex) 
  {
  } 
}

the exception was caught here, event if there's no await for the actual result. It happens that the result of PostAsync is already available and the exception is thrown in this context right??

Is it possible to use ContinueWith to handle exceptions in the current class? For example:

public async Task<Task<Result>> MyAsyncMethod() 
{
    Task<Result> resultTask = await _mySender.PostAsync();
    var exceptionHandlingTask = resultTask.ContinueWith(t => { handle(t.Exception)}, TaskContinuationOptions.OnlyOnFaulted);
    return resultTask;
}

解决方案

This is a lot of questions to pack into a single "question", but OK...

Where does an async Task throw Exception if it is not awaited?

Unobserved Task exceptions are raised by the TaskScheduler.UnobservedTaskException event. This event is raised "eventually" because the Task must actually be garbage collected before its exception is considered unhandled.

As I don't await for the actual Result in the MyAsyncMethod and if PostAsync method throws an exception, in which context is the exception going to be thrown and handled?

Any method that uses the async modifier and returns a Task will put all of its exceptions on that returned Task.

Is there any way I can handle exceptions in my assembly?

Yes, you could replace the returned task, something like:

async Task<Result> HandleExceptionsAsync(Task<Result> original)
{
  try
  {
    return await original;
  }
  catch ...
}

public async Task<Task<Result>> MyAsyncMethod()
{
  Task<Result> resultTask = await _mySender.PostAsync();
  return HandleExceptionsAsync(resultTask);
}

I was surprised that when I tried to change MyAsyncMethod to [synchronously return the inner task] the exception was caught here, even if there's no await for the actual result.

That actually means that the method you're calling is not async Task, as your code example shows. It's a non-async, Task-returning method, and when one of those methods throws an exception, it's treated just like any other exception (i.e., it passes directly up the call stack; it's not placed on the returned Task).

Is it possible to use ContinueWith to handle exceptions in the current class?

Yes, but await is cleaner.

这篇关于如果没有等待异步任务在哪里抛出异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆