【问题标题】:Async exception not caught未捕获异步异常
【发布时间】:2013-03-27 19:20:34
【问题描述】:

这是我与服务器通信的异步方法:

public static Task<bool> ValidateEmail(string email)
    {
        var url = ServerBase + Resources + Authorization + "check_existence";
        var queryString = SerializationHelper.CreateQueryString(new Dictionary<object, object> {{"email", email}});
        try
        {
            return
                HttpHelper.PostAsync(url, queryString, null).ContinueWith(
                    json => SerializationHelper.DeserializeValidationResponse(json.Result));
        } catch (Exception e)
        {
            return TaskErrorHelper.Error<bool>(e);
        }
    }

序列化服务器响应(来自DeserializeValidationResponse 方法)时引发的异常未被捕获。我做错了什么?

UPD:TaskErrorHelper.Error 代码:

internal static Task<T> Error<T>(Exception e)
    {
        var tcs = new TaskCompletionSource<T>();
        tcs.SetException(e);
        return tcs.Task;
    }

【问题讨论】:

    标签: c# asynchronous


    【解决方案1】:

    未捕获序列化服务器响应(来自 DeserializeValidationResponse 方法)时引发的异常。我做错了什么?

    你没有任何错误。错误的是您认为异常处理程序与延续有任何关系。让我们暂时不考虑延续,考虑一下:

    class C
    {
      object obj = null;
      Action action;
      void M()
      {
        N();
        action();
      }
      void N()
      {
         try
         {
           action = ()=>{Console.WriteLine(obj.ToString());};
         }
         catch (Exception ex) 
         { 
           Console.WriteLine("caught!");
         }
      }
    

    您是否认为 catch 处理程序应该捕获 action() 抛出的异常只是因为 action 恰好是在具有处理程序的堆栈帧上创建的?

    这不是异常的工作方式。

    你的情况只是这个小程序的一个更复杂的版本。直到异常处理程序消失很久之后,延续委托才会运行。哎呀,延续甚至可能不在同一个线程上运行!

    那么你如何得到异常呢? 如果继续抛出异常,则会自动捕获并将异常存储在任务中。然后您可以将其拉出任务。

    或者,您可以重写程序以将处理程序的副本放在延续中:

    public static Task<bool> ValidateEmail(string email)
    {
        var url = ...
        var queryString = ...
        try {
            return HttpHelper.PostAsync(url, queryString, null).ContinueWith(
            json => { try { ... } catch(Exception) { ... } });
        } catch( ...
    

    或者,如果你在 C# 5 中使用 async-await,你会得到一些乐趣:

    public static async Task<bool> ValidateEmail(string email)
    {
        var url = ...
        var queryString = ...
        try
        {
            HttpResponseMessage json = await HttpHelper.PostAsync(url, queryString, null);
            SerializationHelper.DeserializeValidationResponse(json.Result));
        } 
        catch (Exception e)
        {
            return false;
        }
        return true;
    }
    

    现在编译器会重写你的代码,让它做你想做的事。 await 的好处是您不必编写任何这种疯狂的“继续”逻辑;编译器会为您完成。

    【讨论】:

    • 使处理程序继续运行确实有帮助,但我想从 catch 子句返回 TaskErrorHelper.Error&lt;bool&gt;(),它返回 Task&lt;bool&gt;。最终结果将是Task&lt;Task&lt;bool&gt;&gt; 类型,这不是我想要的。我在更新中添加了TaskErrorHelper.Error 代码。
    猜你喜欢
    • 2013-02-18
    • 2014-06-03
    • 2020-08-24
    • 1970-01-01
    • 2011-08-12
    • 2013-04-20
    • 1970-01-01
    • 2016-05-10
    • 2015-04-22
    相关资源
    最近更新 更多