3

次の C# コンソール アプリの実行

class Program
{  static void Main(string[] args)
   {  Tst();
      Console.ReadLine();
   }
   async static Task  Tst()
   {
       try
       {
           await Task.Factory.StartNew
             (() =>
                {
                   Task.Factory.StartNew
                       (() =>
                         { throw new NullReferenceException(); }
                         , TaskCreationOptions.AttachedToParent
                        );
               Task.Factory.StartNew
                       (  () =>
                               { throw new ArgumentException(); }
                               ,TaskCreationOptions.AttachedToParent
                       );
                }
             );
    }
    catch (AggregateException ex)
    {
        // this catch will never be target
        Console.WriteLine("** {0} **", ex.GetType().Name);

//******  Update1 - Start of Added code
        foreach (var exc in ex.Flatten().InnerExceptions)
        {
             Console.WriteLine(exc.GetType().Name);
        }
//******  Update1 - End of Added code
    }
    catch (Exception ex)
    {
       Console.WriteLine("## {0} ##", ex.GetType().Name);
    }
 }

出力を生成します:

** AggregateException **

ただし、上記のコードは、 「非同期 - 複数の例外の処理」ブログ記事の最初のスニペットを再現しています。

次のコードは、単一の NullReferenceException または ArgumentException 例外をキャッチします (AggregateException は無視されます)。

問題はどこだ:

  1. 記事がおかしい?
    正しく理解するためにどのコード/ステートメントとどのように変更すればよいですか?
  2. 記事の最初のコード スニペットを再現する際にエラーが発生しましたか?
  3. これは、.NET 4.0/VS2010 Async CTP 拡張機能のバグによるものですが、使用していますか?

Update1(svickの回答に応じて)

コードを追加すると

//******  Update1 - Start of Added code
        foreach (var exc in ex.Flatten().InnerExceptions)
        {
             Console.WriteLine(exc.GetType().Name);
        }
//******  Update1 - End of Added code

生成される出力は次のとおりです。

** AggregateException **
NullReferenceException

したがって、マット・スミスもコメントしたように:

AggregateExceptionキャッチさNullReferenceExceptionれる _ArgumentException

おそらく、この記事はまだ正しいか、少なくとも非常に有用です。私はそれをよりよく読む/理解する/使用する方法を理解する必要があるだけです

Update2(svickの回答に応じて)

svick のコードの実行:

internal class Program
{
  private static void Main(string[] args)
  {
    Tst();
    Console.ReadLine();
  }

  private static async Task Tst()
  {
    try
    {
      await TaskEx.WhenAll
        (
          Task.Factory.StartNew
            (() =>
               { throw new NullReferenceException(); }
            //, TaskCreationOptions.AttachedToParent
            ),
          Task.Factory.StartNew
            (() =>
               { throw new ArgumentException(); }
            //,TaskCreationOptions.AttachedToParent
            )

        );
    }
    catch (AggregateException ex)
    {
      // this catch will never be target
      Console.WriteLine("** {0} **", ex.GetType().Name);

      //******  Update1 - Start of Added code
      foreach (var exc in ex.Flatten().InnerExceptions)
      {
        Console.WriteLine("==="+exc.GetType().Name);
      }
      //******  Update1 - End of Added code
    }
    catch (Exception ex)
    {
      Console.WriteLine("## {0} ##", ex.GetType().Name);
    }
  }
}

生成:

## NullReferenceException ##

出力。

なぜAggregateException生産されないか、捕獲されないのですか?

4

2 に答える 2

6

記事が間違っています。コードを実行すると、awaitedTaskには次のような例外が含まれます。

AggregateException
  AggregateException
    NullReferenceException
  AggregateException
    ArgumentException

ここawaitで (または、より具体的にはTaskAwaiter.GetResult()) が行うことは、外側AggregateExceptionを取得し、最初の子例外を再スローすることです。ここでは、それが別のAggregateExceptionであるため、それがスローされます。

Taskaに複数の例外があり、そのうちの 1 つが直接再スローされるコードの例は、の代わりにawait使用することになります。Task.WhenAll()AttachedToParent

try
{
    await Task.WhenAll(
        Task.Factory.StartNew(() => { throw new NullReferenceException(); }),
        Task.Factory.StartNew(() => { throw new ArgumentException(); }));
}
catch (AggregateException ex)
{
    // this catch will never be target
    Console.WriteLine("** {0} **", ex.GetType().Name);
}
catch (Exception ex)
{
    Console.WriteLine("## {0} ##", ex.GetType().Name);
}
于 2013-05-15T18:59:23.660 に答える