0

async/await パターンを使用した例外処理の (そう思われる) かなり有名な問題に取り組んでいます。具体的には、私のコンテキストは HTTP クライアントにありますが、はるかに単純なテストでも試してみましたが、同じように動作します。

以下のプログラムを考えてみましょう。これは、元のアプリのコンテキストを非常に単純化したバージョンです。


class Program
{
    static void Main(string[] args)
    {
        Test();

        Console.Write("Press any key...");
        Console.ReadKey();
        Console.WriteLine();
    }


    static async void Test()
    {
        var c = new MyClient();

        try
        {
            var uri = new Uri("http://www.google.com/"); //valid address
            var s = await c.GetString(uri);
            Console.WriteLine(s.Length);
        }
        catch (WebException ex)
        {
            Console.WriteLine(ex.Message);
        }

        try
        {
            var uri = new Uri("http://www.foo.bah/"); //non-existent address
            var s = await c.GetString(uri);
            Console.WriteLine(s.Length);
        }
        catch (WebException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}


class MyClient
{
    public async Task<string> GetString(Uri uri)
    {
        var client = new HttpClient();
        return await client.GetStringAsync(uri);
    }
}

プログラムが起動すると、最初の Web サイトのページが文字列としてダウンロードされ、その長さが表示されます。これで問題ありません。その後、無効なアドレスに対して同じ操作が実行されると、クライアントは WebException を発生させます (それが私が望んでいることです) が、キャッチされません。

更新:「キャッチされない」とは、コードが実際には「キャッチ」ブランチを通過せず、例外メッセージをサイレントに表示することを意味します。代わりに、VS IDE によって例外が表示され、デバッグが中断されます。

例外をキャッチする適切な解決策はありますか?

よろしくお願いします。

4

1 に答える 1

1

HttpRequestException例外がnotであることが既にわかっていますがWebException、それでも async-await 演算子の使用法に関するいくつかの重要なことを強調したいと思います。

  1. async voidタイプは fire & forget であり、イベント ハンドラ専用 & のみです。
  2. コンパイラが非同期メソッド内の最初の await 演算子に到達するとすぐに、制御が呼び出し元に戻ります。

コードのデバッグ:-

Test メソッドで async void を使用しているため、コントロールが呼び出し元に戻りConsole.Write("Press any key...");、タスクに関する情報がなくても実行が続行され、ユーザーの入力を待っています。その間、待機していたメソッドからの応答が返ってきて、Test メソッド内で実行が続行されます。

main() 内の行をコメントアウトするか、ユーザーがすぐに入力を提供すると、応答が出力される場合と出力されない場合があることConsole.ReadKey();に気付くでしょう。これは、タスクが実行されるのを待っていないためです。タスクが完了するまで何も入力しないことをユーザーに信頼しているだけです。

解決:-

解決策は、Test() から Task を返し、それが終了するまで待機することです。以下の更新されたコードは、メソッド名の最後に Async を追加することにも注意してください。メソッド。

class Program
{
    static void Main(string[] args)
    {
        Task task = TestAsync();

        Console.Write("Press any key...");
        task.wait();
        //Console.ReadKey();
        Console.WriteLine();
    }


    static async Task<string> TestAsync()
    {
        var c = new MyClient();

        try
        {
            var uri = new Uri("http://www.google.com/"); //valid address
            var s = await c.GetStringAsync(uri);
            Console.WriteLine(s.Length);
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine(ex.Message);
        }

        try
        {
            var uri = new Uri("http://www.foo.bah/"); //non-existent address
            var s = await c.GetStringAsync(uri);
            Console.WriteLine(s.Length);
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine(ex.Message);
        }
         //to avoid compiler error
         return null;
    }
}


class MyClient
{
    public async Task<string> GetStringAsync(Uri uri)
    {
        var client = new HttpClient();
        return await client.GetStringAsync(uri);
    }
}
于 2013-10-17T07:38:24.040 に答える