まず、このサイクルのHabréに投稿された記事の全リスト
GitHubのプロジェクトへのリンク: Dotnetex
複数のリソースで、時々質問がされます。 現在のドメインから出荷済みのアセンブリを作成することは可能ですか? それでは、「さよなら!」を活用するには? どこでも、常に与えられた答えは「いいえ」です。 結局、アンロードできるのはドメインだけです。 したがって、出荷を手配する場合は、アセンブリをドメインに配置し、シリアル化可能なタイプを介したドメイン間の通信を確立する必要があります。 そして、これは非常に遅い相互作用です。 そして、そう言います。 できます。 ニュアンスあり。 また、別のドメインにアップロードします。 ただし、ドメイン間でメソッドを呼び出す場合は、シリアル化をキャンセルします 。
解決する質問:
- ドメインから親にオブジェクトを返す機能を持つドメインを作成する
- アセンブリのアンロード
問題解決
したがって、いつものように、問題が発生した場合は解決します。
- 前の記事で確認したように、メモリは共有され、ドメインに依存しません。 これは、オブジェクトへのポインターを転送する方法を見つけた場合、シリアル化せずにドメイン間でオブジェクトを転送する方法を学習できることを意味します。
一般的なタイプをいくつか見てみましょう。 簡略化するために、mscorlibからIServiceProvider型を取得してみましょう。
出荷の可能性がある友人を作るアセンブリを作成しましょう。
public class Implementation : IServiceProvider { public override string ToString() { return "Awesome"; } public object GetService(Type serviceType) { return new object(); } }
- 次に、ドメインを作成し、このドメインでクラスインスタンスを作成できるクラスを作成します。
public class AppDomainRunner : MarshalByRefObject, IDisposable { private AppDomain appDomain; private Assembly assembly; private AppDomainRunner remoteRunner; private void LoadAssembly(string assemblyPath) { assembly = Assembly.LoadFile(assemblyPath); } public AppDomainRunner(string assemblyPath) { // make appdomain appDomain = AppDomain.CreateDomain("PseudoIsolated", null, new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory }); // create object instance remoteRunner = (AppDomainRunner)appDomain.CreateInstanceAndUnwrap(typeof(AppDomainRunner).Assembly.FullName, typeof(AppDomainRunner).FullName); remoteRunner.LoadAssembly(assemblyPath); } public IntPtr CreateInstance(string typename) { return remoteRunner.CreateInstanceImpl(typename); } private IntPtr CreateInstanceImpl(string typename) { return EntityPtr.ToPointer(assembly.CreateInstance(typename)); } public void Dispose() { assembly = null; remoteRunner = null; AppDomain.Unload(appDomain); }
- 次に、IoCコンテナのクラスを作成しましょう。
public class Container : IDisposable { private AppDomainRunner appdomain; private Dictionary<Type, Object> instances = new Dictionary<Type, object>(); public Container(string assemblyName) { appdomain = new AppDomainRunner(Path.Combine(System.Environment.CurrentDirectory, assemblyName)); } public void Register<TInterface>(string fullTypeName) { instances.Add(typeof (TInterface), EntityPtr.ToInstance<Object>(appdomain.CreateInstance(fullTypeName))); } public TInterface Resolve<TInterface>() { return (TInterface)(instances[typeof (TInterface)]); } public void Dispose() { appdomain.Dispose(); } }
最後のコードは次のコードを使用しています。
static void Main(string[] args) { using (var container = new Container("library.dll")) { container.Register<IServiceProvider>("IocLibrary.Implementation"); var serviceProvider = container.Resolve<IServiceProvider>(); Console.WriteLine("calling method without proxy: {0}", serviceProvider); Console.WriteLine("Current domain assemblies: {0}", string.Join(", ", AppDomain.CurrentDomain.GetAssemblies().Select(asm => asm.GetName().Name).ToArray())); } }
結論
彼らが言うように、出荷されたタイプを作ることは不可能ですが、望むなら、できます。 ドメイン間でオブジェクトへのポインタを何らかの方法で転送するだけで、同じ位置で使用できます。
マイナスのメソッドは1つしかありません。アセンブリをアンロードした後にオブジェクトを使用する権利はありません。 これは1つの単純な理由からマイナスです。出荷の順序とオブジェクトへの参照の損失をさらに制御する必要があるからです。 しかし、一般的に、これは問題ではありません=)