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はキャッチされません。私は何を間違っていますか?

UPD: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!");
     }
  }

ハンドラーを持つスタック フレームでたまたま作成されたというaction()理由だけで、catch ハンドラーがスローされた例外をキャッチする必要があると思いますか?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-awaitC# 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 に答える