C#で便利な例外処理コード

このエントリーをはてなブックマーク
Share
2009.02.10    C#, Windows, 馬場   タグ: , , —    baba   

C#でプログラムを書いているとき、エラーが発生したらとりあえずthrowしますよね?
その例外は、どこかでcatchして、メッセージボックスなりエラーログなりで出力しなくてはいけません。
忘れると、例外発生時に情報無しで落ちてしまって、情報収集がしにくくなります。

しかし、開発中にきちんとしたエラー処理を書くのも面倒なので、とりあえず捕捉しなかったエラーは全部1カ所で処理したいものです。
単純にApplication.Run()をtry-catchで囲っても、正しく処理できません。
この場合は、ApplicationのThreadException と ThreadのUnhandledException を使います。

[参考]
適切に処理されなかった例外をキャッチするには?

下記のサンプルコードのようにすると、catchされなかった例外はメッセージボックスを表示し、同じディレクトリのerror.txtに詳細が記録されます。
開発中でエラーポリシーも詳細が決まっていないとき、とりあえずこのような処理を入れておくと、デバッグモード以外で起動してもエラー詳細が見られて便利です。


//サンプルコード
[STAThread]
static void Main()
{
    //エラーハンドラを登録
    Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
    Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(Program_UnhandledException);

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
}

static void Program_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    Exception ex = e.ExceptionObject as Exception;
    if (ex != null)
    {
        ShowError(ex, "UnhandledException");
    }
}

static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
    ShowError(e.Exception, "ThreadException");
}

static void ShowError(Exception ex, string title)
{
    MessageBox.Show("プログラム中で補足されなかったエラーが発生しました。詳細はエラーログをごらん下さい。", title);

    StreamWriter stream = new StreamWriter("error.txt", true);    
    stream.WriteLine("[" + title + "]");
    stream.WriteLine("[message]\r\n" + ex.Message);
    stream.WriteLine("[source]\r\n" + ex.Source);
    stream.WriteLine("[stacktrace]\r\n" + ex.StackTrace);
    stream.WriteLine();
    stream.Close();
}

System.Windows.Forms.Timer が動かない

このエントリーをはてなブックマーク
Share

C#でスレッドを使うときの注意です。

System.Windows.Forms.Timer はお手軽でよく使いますが、このTimerはUIスレッドでのみ動くためなのか、別スレッドから呼ぶと動かないみたいです。

System.Threading.Thread や System.Threading.Timer、TcpListener::BeginReceive() などで作ったスレッド内で System.Windows.Forms.Timer を作ってStart()メソッドを呼んでも、Tickはいくら待っても呼ばれません。


//テストコード
Thread thread = new Thread(new ThreadStart(delegate {
    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer { Interval = 1000 };
    timer.Tick += new EventHandler(delegate { MessageBox.Show("HOGE");});
    timer.Start();
}));
thread.Start();

上記のテストコードで、メッセージボックスは永久に出ません。
System.Windows.Forms.Timer を System.Threading.Timer に変えれば動くので、これは System.Windows.Forms.Timer の制約のようです。

ネットワークでパケット受信をトリガに処理を始めるときなど、うっかりミスしないように気をつけましょう。

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.