2017-02-01 6 views
1

私の理解には何かがないと思います。私がConsole.WriteLineが実行されたキャッチにブレークポイントを置くと、停止しません。例外がキャッチされないのはなぜですか?

private static void Main(string[] args) 
{ 
    Process(async() => await ClientMethod()).Invoke(); 
    Console.Read(); 
} 

public static async Task ClientMethod() 
{ 
    throw new Exception("Test"); 
} 

public static Action Process(Action functor) 
{ 
    return() => 
    { 
     try 
     { 
      functor(); 
     } 
     catch (Exception) 
     { 
      // Handle exceptions ? 
      Console.WriteLine("In the catch"); 
      throw; 
     } 
    }; 
} 

しかし、私はこれに私のコードを変更した場合、非同期動作を除去することで、ブレークポイントにヒットされています

private static void Main(string[] args) 
{ 
    Process(() => ClientMethod()).Invoke(); 
    Console.Read(); 
} 

public static void ClientMethod() 
{ 
    throw new Exception("Test"); 
} 

例外が最初のケースでキャッチされていないのはなぜ?どのように私はそれをキャッチできますか?

編集:私はこれに私のコードを変更するが、それはまだ同じです:

private static void Main(string[] args) 
{ 
    var res = Process(async() => await ClientMethod()).Invoke(); 
    Console.Read(); 
} 

public static async Task<string> ClientMethod() 
{ 
    throw new Exception("Test"); 
} 

public static Func<T> Process<T>(Func<T> functor) 
{ 
    return() => 
    { 
     try 
     { 
      return functor(); 
     } 
     catch (Exception) 
     { 
      // Handle exceptions ? 
      Console.WriteLine("In the catch"); 
      throw; 
     } 
    }; 
} 

答えて

3

プロセス内のアクションがasync voidとして呼び出されているため。

引用:Async/Await - Best Practices in Asynchronous Programming

から非同期のボイドの方法は異なるエラー処理意味論を持っています。 例外がasync Taskまたはasync Task<T>メソッドからスローされると、その 例外がキャプチャされ、タスクオブジェクトに配置されます。 async void メソッドでは、Taskオブジェクトは存在しないため、 非同期voidメソッドからスローされた例外は、非同期voidメソッド が起動したときにアクティブだった SynchronizationContextで直接発生します。

+0

だから私は代わりに、それが動作するはずアクションの戻り値でのFuncを持っていた場合は? – Peekyou

+0

アクションの代わりにFuncを使用して質問を編集しました。したがって、非同期のvoidメソッドではありませんが、例外はまだキャッチされていません。 – Peekyou

+0

いいえ。 – Nkosi

1

最初のコードの問題は、Actionasync voidメソッドを作成していることです。いくつかの理由からavoid async voidにする必要があります - そのうちの1つは例外処理が奇妙です(例外はどんな種類の合理的な方法でもasync voidメソッドから伝播しません)。

あなたの2番目のコードは奇妙です。 TTask<string>であることを覚えていると、何が起こっているのかをより明確に見ることができます。だから、あなたのラッパーデリゲートはTask<string>を返します。その例外を観察することはありません。 To observe exceptions from a task-returning method, you should await the task it returnsであり、tryブロックのコードはawaitではありません。

解決策は、最初の例に戻ることです。あなたがしたいのは、Actionデリゲート型を非同期の同等のwhich is Func<Task>に変更することです。ここから、解決策は、より自然に流れ:

public static Func<Task> Process(Func<Task> functor) 
{ 
    return async() => 
    { 
    try 
    { 
     await functor(); 
    } 
    catch (Exception) 
    { 
     Console.WriteLine("In the catch"); 
     throw; 
    } 
    }; 
} 

使用法:

await Process(async() => await ClientMethod()).Invoke(); 

public static async Task ClientMethod() 
{ 
    throw new Exception("Test"); 
} 
+2

この時点でラムダが「非同期」になる理由も、ラムダを持つことさえありません。メソッドグループとして 'ClientMethod'を渡すことができます。もし本当にラムダが必要ならば、非同期ラムダはうまくいくでしょう。 – Servy

+0

@Servy:はい、しかし、理解のレベルが与えられているので、私は使用コードをまったく整理しませんでした。 –

関連する問題