プラグインを別のアプリ ドメインにロードするメイン アプリケーションがあります。そのプラグインでは、メイン アプリから渡されたオブジェクトのイベントをサブスクライブしています。別のアプリ ドメインでプラグインを作成すると、プラグイン dll がそのドメインに読み込まれますが、メイン アプリ オブジェクトのイベントをサブスクライブすると、プラグイン dll がメイン アプリ ドメインにも読み込まれます。
プラグイン ドメインをアンロードできるようにしたい (これは機能します) が、その dll がメイン アプリ ドメインに読み込まれているため (そのサブスクリプションのため)、現在実行できないプラグイン dll を置き換えることもできる必要があります。
これが私の実際のコードに似たサンプルコードです(簡潔にするため):
プラグインのインスタンス化に使用される IContract というインターフェイスがあります。
namespace PluginShared
{
public interface IContract
{
void Init(IHostObject hostObject);
void Shutdown();
}
}
これは別の PluginShared.dll にあります。そのインターフェイスは、メイン アプリで作成されたオブジェクトを渡すための Init と、プラグインのアプリ ドメインがアンロードされる前にプラグインで必要なクリーンアップを行うための Shutdown の 2 つのメソッドを定義します。
IHostObject は同じ PluginShared.dll にあり、次のようになります。
namespace PluginShared
{
public interface IHostObject
{
event Action ValueChanged;
}
}
このインターフェイスは、メイン アプリの HostObject によって実装されます。
public class HostObject : MarshalByRefObject, IHostObject
{
public event Action ValueChanged;
public void Foo()
{
if (ValueChanged != null)
ValueChanged();
}
}
メイン アプリ コードはプラグインを読み込み、Init を呼び出し、HostObject インスタンスをプラグインに渡します。次に、プラグインで Shutdown を呼び出し、プラグイン ドメインをアンロードします。
private void LoadUnloadPlugin()
{
IHostObject hostObject = new HostObject();
AppDomain pluginAppDomain = AppDomain.CreateDomain("PluginAppDomain");
IContract plugin = (IContract)pluginAppDomain.CreateInstanceFromAndUnwrap(@".\Plugin1.dll", "Plugin1.Plugin1");
plugin.Init(hostObject);
plugin.Shutdown();
AppDomain.Unload(pluginAppDomain);
}
プラグインは独自の Plugin1.dll です。
namespace Plugin1
{
public class Plugin1 : MarshalByRefObject, IContract
{
IHostObject myHostObject;
public void Init(IHostObject hostObject)
{
myHostObject = hostObject;
myHostObject.ValueChanged += OnValueChanged;
}
public void Shutdown()
{
myHostObject.ValueChanged -= OnValueChanged;
myHostObject = null;
}
private void OnValueChanged()
{
// Do Stuff
}
}
}
繰り返しますが、問題は myHostObject.ValueChanged += OnValueChanged; の場合です。実行すると、Plugin1.dll がメイン アプリ ドメインに読み込まれ、dll がロックされて削除できなくなります。
ところで。さまざまなオブジェクトによって起動されるさまざまな ValueChanged のようなイベントを定義する IHostObject のようなインターフェイスがたくさんあります。また、一般的に、私のプラグインはすべてのオブジェクトのイベントをサブスクライブしているわけではありません。上記のサンプル コードの ValueChanged イベントは、イベントを発生させる代わりにプラグインごとに呼び出される IContract のメソッドに簡単に置き換えることができるため、これについて言及していますが、私の実際の実装では、よりイベントのようなアプローチが必要です。
プラグインdllをメインアプリドメインにロードせずに、メインアプリから選択した通知/イベントを取得できるようにするために使用できる方法/テクニック/パターンはありますか?