C# の finally と .NET の BeginInvoke/EndInvoke について
private void processTimer_Elapsed(object sender, EventArgs e) { try { if (processing) { return; } processing = true; // 更新を通知する。 IAsyncResult ar = timerSyncObj.BeginInvoke( new EventHandler(NotifyHandler), new object[] { this, new InvokerEventArgs(TaskChangedEnum.Changed) }); timerSyncObj.EndInvoke(ar); // (A) } finally { processing = false; if (notifyRequired) { IAsyncResult ar = timerSyncObj.BeginInvoke( new EventHandler(NotifyHandler), new object[] { this, new InvokerEventArgs(TaskChangedEnum.Success) }); timerSyncObj.EndInvoke(ar); // (B) } } }
というコードを書いているのだが、(A) の EndInvoke の時点で System.ObjectDisposedException が出てデバッガーが一時停止し、processing == false になっている。(変数 processing に対する書き込みはこのメソッド内でしかやっていない。)
.NET のコンテキストの扱いと finally の仕様のためだと思うのだが、どうもややこしくて分かりづらい。
2009年9月26日追記: 勘違いしていたようだ。別に finally が特殊な仕様な訳ではない。メソッドに再入しているためだ。try から抜けない(とうぜん processTimer_Elapsed メソッドも抜けない)内に BeginInvoke で呼ばれた先でタイマーの発火が起こり、再び processTimer_Elapsed メソッド内に入り、if (processing) で合致するためすぐに return するがその際に finally が実行されて変数 processing に false を代入しているだけだ。