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

标签 c# .net exception-handling async-await

今天我读了很多关于 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");
    }
}


测试通过,但输出包含:

System.Exception
test excpetion
   at AsyncHttpListenerTest.AsyncHttpListener.HandleContext(HttpListenerContext context) in AsyncHttpListener.cs: line 30
   at AsyncHttpListenerTest.AsyncHttpListener.d__0.MoveNext() in AsyncHttpListener.cs: line 25
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.b__1(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

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

最佳答案

让你的方法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 完成,然后再考虑测试完成。

关于c# - 如何从异步方法向调用者抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14379845/

相关文章:

performance - D 中异常处理的开销

php - 在 PHPUnit 异常上禁用堆栈跟踪

c# - 替代 Application.DoEvents()

c# - 从网络服务返回类型列表

c# - 在未经检查的语句中出现溢出错误

c# - 组装 ... 内部和外部命名空间

c# - GitHub API 更新文件

c# - 我可以在尝试使用或返回枚举值时避免强制转换它吗?

c# - 是否可以设置 DataGrid (SWF) 以调整到最佳大小?

c# - 防止 "The remote host closed the connection"异常的可接受方法