memo:BeginInvokeしたときの例外
ちょっとキモいのでメモ。
ラムダ式とBeginInvokeでなんだか気持ちよくなっていたら
例外の辺りで戸惑ったのでメモ。
詳しくは
http://d.hatena.ne.jp/akiramei/20060126/p1
でいいのかしら。
要するにスレッド分けたらmainに例外持ってくるのはしんどい、ということでしょうか?
static void Main(string[] args) { //まず、delegateをBeginInvokeでcallしたときに発生した例外はどうなるか。 Func<int> dele = () => { throw new Exception("delegateで例外発生"); }; //普通にcallしたらスレッドとか関係ないのでmainで補足が可能 try { dele(); } catch (Exception ex) { Console.WriteLine(ex.Message); } //begininvoke call 例外はどこかへ行ってしまう。キモいですね。 dele.BeginInvoke(null, null); /*begininvokeしたら、endinvokeするcallbackを書きましょう * という作法が存在するらしいので則る。*/ try { dele.BeginInvoke(callb, null); } catch (Exception ex)//=>このcatchは実行されない { Console.WriteLine("async exception:" + ex.Message); } //begininvokeで発生した(別スレッドで発生した例外はmainにはかえってこない。) //ラムダ式だと急遽、ってパターンだとおもうのです。 //パターン:おっと、ここで急遽ロジックを追加しなくっちゃぁ! dele += () => { throw new Exception("急遽追加したらまた例外が発生"); }; foreach (Func<int> instance in dele.GetInvocationList())//Delegate[]を挟むのが作法 { instance.BeginInvoke(callb, null); } //まとめ。基本的にBeginInvokeの先の例外は //delegate先のメソッドの中か、遅くてもcallbackで処理してしまう。 //ダメならプログラム落とせ。 //mainに例外は来ない。 while (true) { } } //callback関数 public static void callb(IAsyncResult ret) { System.Runtime.Remoting.Messaging.AsyncResult ar = (System.Runtime.Remoting.Messaging.AsyncResult)ret; Func<int> ins = (Func<int>)ar.AsyncDelegate;//型が合致していればOK try { int retvalue = ins.EndInvoke(ret); } catch (Exception ex) { Console.WriteLine(ex.Message); //throw ex;//mainで補足出来ると思ったら大間違いだ! //※どうしてもmain側に「通知」したいならここに何か書く。 } }
try-catchでは例外をmainに持って行くのは無理目っぽい。どうしてもmain側につなげたいならば
catchからmainのメソッドなり、main側でeventを作っておいて対応することに成るのだろう。
でもこれはあくまで「失敗の通知」なのでエラーを制御することはない。エラー制御はあくまで
delegateメソッドやcallbackなどの「スレッド側」で行わなくてはならないっぽいです。