1

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

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未捕获序列化服务器响应(来自方法)时引发的异常。我究竟做错了什么?

更新:TaskErrorHelper.Error代码:

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

1 回答 1

10

未捕获序列化服务器响应(来自 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( ...

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

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是您不必编写任何这种疯狂的“继续”逻辑;编译器会为你做这件事。

于 2013-03-27T20:03:46.297 回答