知ってると、ちょっと便利かもしれないTips。メモメモ。
AppDomainクラスには、アンロード時に発行されるDomainUnloadイベントがあります。
このイベントには、注意点がありまして
既定のアプリケーションドメインの場合は、イベントが発行されない。
という点があります。有効となるのは、自分で作成したアプリケーションドメインの場合です。
既定のアプリケーションドメインは、Unload出来ない(実行するとエラーとなる)ので、当たり前といえば当たり前ですが。
で、既定のアプリケーションドメインの場合はどうするのかという事になるのですが
以下のイベントを利用します。
public event EventHandler ProcessExit
ちなみに、このイベントは自分で作成したアプリケーションドメインの場合でもハンドルできます。
てことは、DomainUnloadイベントとProcessExitイベントの両方をハンドルすることが出来ます。
その場合、以下のようにイベントが発行されます。
- AppDomain.Unloadメソッドで、対象アプリケーションドメインをアンロードするとDomainUnloadイベントが発生される。ProcessExitイベントは発生しない。
- AppDomain.Unloadメソッドを呼ばずに、処理を終了するとProcessExitイベントが発生する。
以下、サンプルです。
#region AppDomainSamples-02 /// <summary> /// AppDomainクラスのサンプルです。 /// </summary> public class AppDomainSamples02 : MarshalByRefObject, IExecutable { public void Execute() { AppDomain defaultDomain = AppDomain.CurrentDomain; AppDomain anotherDomain = AppDomain.CreateDomain("AnotherAppDomain"); // // DomainUnloadイベントのハンドル. // // 既定のアプリケーションドメインでは、Unloadは登録できるが発行されることは // 無いので、設定する意味がない. //defaultDomain.DomainUnload += AppDomain_Unload; anotherDomain.DomainUnload += AppDomain_Unload; // // ProcessExitイベントのハンドル. // defaultDomain.ProcessExit += AppDomain_ProcessExit; anotherDomain.ProcessExit += AppDomain_ProcessExit; // // 既定のアプリケーションドメインをアンロードしようとするとエラーとなる. // ** appdomain をアンロード中にエラーが発生しました。 (HRESULT からの例外: 0x80131015) ** //AppDomain.Unload(defaultDomain); // // AppDomain.Unloadを呼び出すと、DomainUnloadイベントが発生する. // AppDomain.Unloadを呼び出さずにプロセスが終了させようとすると // ProcessExitイベントが発生する。両方のイベントが同時に発生することは無い. // // 以下をコメントアウトすると、ProcessExitイベントが発生する. // AppDomain.Unload(anotherDomain); } void AppDomain_Unload(object sender, EventArgs e) { AppDomain domain = sender as AppDomain; Console.WriteLine("AppDomain.Unload: {0}", domain.FriendlyName); } void AppDomain_ProcessExit(object sender, EventArgs e) { // // ProcessExitイベントには、タイムアウトが存在する。(既定は2秒) // 以下、MSDNの記述. // (http://msdn.microsoft.com/ja-jp/library/system.appdomain.processexit.aspx) // // 「プロセス シャットダウン時における全ファイナライザーの合計実行時間が限られているように、ProcessExit の // すべてのイベント ハンドラーに対して割り当てられる合計実行時間も限られています。 既定値は 2 秒です。」 // // 以下のコメントを外して実行すると、タイムアウト時間を過ぎるので // イベントをハンドルしていても、後続の処理は実行されない。 // // わざとタイムアウト時間が過ぎるように待機. //Console.WriteLine("AppDomain.ProcessExit Thread.Sleep()"); //Thread.Sleep(TimeSpan.FromSeconds(3)); AppDomain domain = sender as AppDomain; Console.WriteLine("AppDomain.ProcessExit: {0}", domain.FriendlyName); } } #endregion
実行結果は、以下になります。MySamples.exeが既定のアプリケーションドメインです。
AppDomain.Unload: AnotherAppDomain AppDomain.ProcessExit: MySamples.exe
上記サンプルにて、手動で作成したアプリケーションドメイン (anotherDomain)をUnloadせずに
処理を終了すると、以下のようになります。
AppDomain.ProcessExit: MySamples.exe AppDomain.ProcessExit: AnotherAppDomain
尚、上記のサンプルにもコメントで記載している通り、ProcessExitイベントには
タイムアウト制限があります。既定では2秒となっています。2秒以内に処理を終えないと
タイムアウトと見なされ、処理が打ち切られます。
以下は、上記のサンプルのAppDomain_ProcessExitメソッドにて
わざとタイムアウトするようにして、実行した結果です。
AppDomain.Unload: AnotherAppDomain AppDomain.ProcessExit Thread.Sleep()
後続の処理が打ち切られているのが分かります。
以下、参考情報です。
- AppDomain.DomainUnload イベント
- AppDomain.ProcessExit イベント
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ