2013-05-14 13 views
7

私は、次のコードを実行しようとしている:私はExceptionは、次の場所に巻き込まれることが期待この例外が検出されないのはなぜですか?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var task = Task.Factory.StartNew(() => 
      { 
       throw new ApplicationException("message"); 
      }); 
     try 
     { 
      task.ContinueWith(t => Console.WriteLine("End")); 
     } 
     catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 
    } 
} 

を:

 catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 

しかし、これは起きていません。なぜこれはそうですか?あなたの文原因

+0

です。回答では、何がどのように実行されるのか(「例外」は検出されません)は対処されています。この理論的根拠は理解することが重要であり、Stephen Toubの記事[.NET 4.5のタスク例外処理](http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876)で説明されています。 aspx)は必読です] –

答えて

9

その前に...キャッチは...すべての例外をキャッチします - これはしませんまだ完了しています。

タスクを印刷しても完了するのを待つか、値を取得しようとしません。

あなたがあなたのコードを変更した場合:

try 
{ 
    task.Wait(); 
} 

... そして私はそれが例外をキャッチすることを期待したいです。

(私は以前Task<T>.Resultを使用していたが、私はこれに気づくことは戻り値のない作業なので、それだけで非ジェネリックTaskだろう。)

+0

@NominSim No.「StartNew」が返ってくると、デリゲート自体はまだ実行されていません。例外にまだ到達していない場合でも、その行で例外をスローすることはできません。 – Servy

+1

@NominSim:これは、ブロックする 'Result'プロパティの取得によって捕捉されます。 –

+1

@ NominSim 'ApplicationException'は他のスレッドからスローされます。そのスレッドでは、提供された匿名デリゲートを呼び出すと、最終的に( 'Task'コードの内部にあるcatchブロック内で)捕捉されます。タスクの作成時にメインスレッドから再スローされません。メインスレッドがタスクを待機すると、タスクが完了すると、タスクがトップレベルの例外で終了したことがわかります。その例外は、 'Wait'メソッドの実装が明示的に行うものなので、メインスレッドの中で(ラップされた' AggregateException'で)再スローされます。 – Servy

-4

は、tryではありませんが、中括弧を試すの中からあなただけのtaskをプリントアウトしている

+3

あなたは仕事の性質を誤解したと思います。 –

+0

これは単に真実ではありません。簡単な反例: 'try'ブロックの本体を' task.Result'に設定してください。実際には、タスクを定義するデリゲートで生成された例外が再生成されてしまいます。 – Servy

+0

@Jon Skeet> downvotesを見て、私は本当にすべての疑問を誤解していると思う:-) –

1

方法Task作品、呼び出して終了コード最終的にStartNewに渡されたデリゲートがキャッチされ、Exceptionがタスクのインスタンスフィールドに格納されます。この例外はtask.Exceptionプロパティを調べることで検査できます。 Console.WriteLine(task)という行は、task.ToStringを内部で呼び出すだけです。このメソッドでは、例外がスローされたり再スローされることはありません。

ただし、特定の状況では、キャッチされた例外が再スローされます。 2つの例は、ResultにアクセスしてWaitを呼び出すときと、awaitのときにC#5.0のタスクを呼び出すときです。

次のコード

try 
{ 
    task.Wait(); 
} 
catch (AggregateException aex) 
{ 
    Console.Write(aex.InnerException.Message); 
} 

再スローされ、例外メッセージが印刷される格納された例外が発生します。

+0

セミコロンを使用しても、プロパティアクセスは単独のステートメントとして使用できません。 –

+0

@LuisFilipe私は既に彼が言及している間違いを編集しました。改訂履歴を見るだけです。 – Servy

+0

@LuisFilipe実際、私は5分のウィンドウ内で修正したので、改訂履歴には含まれません。私は固定してから間違いがありました。 – Servy

-2

AggregateExceptionとApplicationExceptionは、両方とも同じクラスSystem.Exceptionの子です。 AggregateException は、 ApplicationException

+1

これは無関係です。 OPの 'try'ブロックからどんな種類の例外もスローされません。 – Servy

+0

ええ、私は手足の外に出て、 '新しいApplicationException(" message ");をスローすると、このタスクの実際の実装ではないと言うでしょう。この例を作成するにはタイプミスで、実際の問題とは何の関係もありませんでした。 –

+0

@NickFreeman Nope。それはまったく真実ではありません。 'Task'クラスは、本体内からスローされた例外を' AggregateException'でラップするので、その例外の使用が適切です。私の答えで説明しているように、問題はOPが 'task.Wait()'を使う必要があるということです。そのわずかな変更は、プログラムが意図した通りに正確に動作するようにします。 – Servy

関連する問題