如何从异步方法向调用者抛出异常?

Posted

技术标签:

【中文标题】如何从异步方法向调用者抛出异常?【英文标题】:How to throw exception to caller from async method? 【发布时间】:2013-01-01 00:53:37 【问题描述】:

今天我读了很多关于 async/await 的内容,这让我大吃一惊。 我不明白为什么下面的测试通过了。

[Test]
public void Test()

    var listener = new AsyncHttpListener();
    listener.ListeningAsync();

    try
    
        new WebClient().DownloadString("http://localhost:8080/");
    
    catch (Exception)
    
    

    listener.Close();


public class AsyncHttpListener

    private readonly HttpListener listener;

    public AsyncHttpListener()
    
        listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:8080/");
        listener.Start();
    

    public void Close()
    
        listener.Close();
    

    public async void ListeningAsync()
    
        var context = await listener.GetContextAsync();
        HandleContext(context);
    

    private void HandleContext(HttpListenerContext context)
    
        throw new Exception("test excpetion");
    

测试通过,但输出包含:

系统异常 考试成绩 在 AsyncHttpListener.cs 中的 AsyncHttpListenerTest.AsyncHttpListener.HandleContext(HttpListenerContext 上下文):第 30 行 在 AsyncHttpListener.cs 中的 AsyncHttpListenerTest.AsyncHttpListener.d__0.MoveNext():第 25 行 --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.AsyncMethodBuilderCore.b__1(对象状态) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext、ContextCallback 回调、 对象 状态、 布尔型 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch()

我希望异常会从任务线程(HandleContext() 方法)传输到调用者上下文并且测试失败。我怎样才能得到这种行为?

【问题讨论】:

【参考方案1】:

将您的方法设为async Task 而不是async void,并将您的测试方法设为async Task 而不是void

public async Task ListeningAsync()

    var context = await listener.GetContextAsync();
    HandleContext(context);


[Test]
public async Task Test()

    var listener = new AsyncHttpListener();
    await listener.ListeningAsync();

    try
    
        new WebClient().DownloadString("http://localhost:8080/");
    
    catch (Exception)
    
    

    listener.Close();

避免async void 有几个很好的理由。错误处理就是其中之一。从async void 方法引发的错误直接转到方法启动时的当前SynchronizationContext

您的测试通过的原因是因为async 方法可能会在完成之前返回给调用者。测试运行程序看到测试方法返回(尚未抛出异常),并将其标记为“通过”。如果您从测试方法返回 Task,则测试运行者知道在考虑测试完成之前等待 Task 完成。

【讨论】:

以上是关于如何从异步方法向调用者抛出异常?的主要内容,如果未能解决你的问题,请参考以下文章

如何捕获ctypes中抛出的异常?

JAVA异常处理

java基础之异常

java异常处理 throw RuntimeException时不需要同时方法中声明抛出throws 异常等待调用者catch进行捕获 子父类异常问题

Java基础——异常处理

java-异常处理和线程的一些简单方法及使用