たまに別のAppDomainを作成して、処理を実行することがあるので
実行の方法について個人的にメモメモ。
方法はいくつかあるのですが、私がよく利用するのは以下の3つ。
- AppDomain.ExecuteAssemblyを利用する。
- AppDomain.DoCallbackを利用する。
- AppDomain.CreateInstanceAndUnwrapを利用して、プロキシを取得し実行.
既に実行するためのアセンブリが存在している場合は、ExecuteAssemblyがお手軽。
でも、実行するだけなので細かい調整が出来ない。
DoCallBackは、デリゲートを渡せるので便利。
必要な処置を行った後、ExecuteAssemblyを呼び出したりする。
CreateInstanceAndUnwrapは、一番フレキシブルな方法。
以下、サンプルです。
予め、ExecuteAssemblyメソッドで利用するためのアセンブリを以下のように作成し
"AnotherAppDomain.exe"として配置しているとします。
using System; using System.Collections.Generic; using System.Linq; namespace AnotherAppDomain { class Program { static void Main() { new Program().Execute(); } void Execute() { var domain = AppDomain.CurrentDomain.FriendlyName; Console.WriteLine("Run on AppDomain:{0}", domain); } } }
呼び出し部分。
#region AppDomainSamples-04 public class AppDomainSamples04 : MarshalByRefObject, IExecutable { public void Execute() { // // AppDomainを利用して、別のAppDomainで処理を実行するための方法は、いくつか存在する。 // // ・AppDomain.ExecuteAssemblyを利用する。 // ・AppDomain.DoCallbackを利用する。 // ・AppDomain.CreateInstanceAndUnwrapを利用して、プロキシを取得し実行. // var currentDomain = AppDomain.CurrentDomain; var anotherDomain = AppDomain.CreateDomain("AD No.2"); // // AppDomain.ExecuteAssemblyを利用して実行. // // ExecuteAssemblyメソッドには、アセンブリ名を指定する。 // ここで指定するアセンブリは実行可能である必要があり、エントリポイントを持っている必要がある。 // anotherDomain.ExecuteAssembly(@"AnotherAppDomain.exe"); // // AppDomain.DoCallbackを利用する. // // DoCallbackは指定されたデリゲートを実行するためのメソッド. // 別のAppDomainのDoCallbackにデリゲートを渡す事により // 処理がそのアプリケーションドメインで実行される。 // // 当然、値渡し(Serializable)と参照渡し(MarshalByRefObject)によって実行結果が異なる場合がある. // // Staticメソッド Console.WriteLine("----------[Static Method]--------"); currentDomain.DoCallBack(CallbackMethod_S); anotherDomain.DoCallBack(CallbackMethod_S); Console.WriteLine("---------------------------------"); // インスタンスメソッド. Console.WriteLine("---------[Instance Method]-------"); currentDomain.DoCallBack(CallbackMethod); anotherDomain.DoCallBack(CallbackMethod); Console.WriteLine("---------------------------------"); // 値渡し (Serializable) var byvalObj = new MarshalByVal(); Console.WriteLine("---------[Serializable]----------"); currentDomain.DoCallBack(byvalObj.CallbackMethod); anotherDomain.DoCallBack(byvalObj.CallbackMethod); Console.WriteLine("---------------------------------"); // 参照渡し (MarshalByRefObject) // MarshalByRefObjectを継承しているため、以下の例では必ずデフォルトドメインで実行されることになる。 var byrefObj = new MarshalByRef(); Console.WriteLine("-------[MarshalByRefObject]------"); currentDomain.DoCallBack(byrefObj.CallbackMethod); anotherDomain.DoCallBack(byrefObj.CallbackMethod); Console.WriteLine("---------------------------------"); // // AppDomain.CreateInstanceAndUnwrapを利用する。 // プロキシを取得して処理を実行する. // var asmName = typeof(MarshalByRef).Assembly.FullName; var typeName = typeof(MarshalByRef).FullName; var obj = (MarshalByRef) anotherDomain.CreateInstanceAndUnwrap(asmName, typeName); Console.WriteLine("-------[CreateInstanceAndUnwrap]------"); obj.CallbackMethod(); Console.WriteLine("--------------------------------------"); AppDomain.Unload(anotherDomain); } static void CallbackMethod_S() { Utils.PrintAsmName(); } void CallbackMethod() { Utils.PrintAsmName(); } [Serializable] public class MarshalByVal { public void CallbackMethod() { Utils.PrintAsmName(); } } public class MarshalByRef : MarshalByRefObject { public void CallbackMethod() { Utils.PrintAsmName(); } } static class Utils { public static void PrintAsmName() { var domain = AppDomain.CurrentDomain.FriendlyName; Console.WriteLine("Run on AppDomain:{0}", domain); } } } #endregion
実行すると以下のようになります。
Run on AppDomain:AD No.2 ----------[Static Method]-------- Run on AppDomain:MySamples.exe Run on AppDomain:AD No.2 --------------------------------- ---------[Instance Method]------- Run on AppDomain:MySamples.exe Run on AppDomain:MySamples.exe --------------------------------- ---------[Serializable]---------- Run on AppDomain:MySamples.exe Run on AppDomain:AD No.2 --------------------------------- -------[MarshalByRefObject]------ Run on AppDomain:MySamples.exe Run on AppDomain:MySamples.exe --------------------------------- -------[CreateInstanceAndUnwrap]------ Run on AppDomain:AD No.2 --------------------------------------
あと、以前にも、AppDomainについてはいつくか記事を記述しているのでご参考までに。
- AppDomain毎の統計情報を取得する (AppDomain, MonitoringIsEnabled, .NET 4.0, 参照されているオブジェクトのバイト数, メモリ割り当てサイズ, 合計プロセッサ時間)
- AppDomainクラスのDomainUnloadイベントとProcessExitイベントについて (AppDomain, DomainUnload, ProcessExit, タイムアウト時間, 2秒, 既定のAppDomain)
- 例外発生時catchブロックよりも先に例外通知を受ける。 (.NET 4.0, AppDomain, FirstChanceException, System.Runtime.ExceptionServices)
- MarshalByRefObjectとSerializableのちょっとした違い (アプリケーションドメイン, 境界越え, Assembly, AppDomain, CreateInstanceAndUnwrap)
- アプリケーションで未ハンドルの例外を補足する。(Application.ThreadException, AppDomain.UnhandledException)
以下、参考情報です。
- AppDomain.DoCallBackメソッド
- AppDomain.ExecuteAssemblyメソッド
- AppDomain.CreateInstanceAndUnwrap
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ