時間がない人のために、問題を短いバージョンと長いバージョンに分けました。
短縮版:
プロバイダーとコンシューマーのプラグインを備えたシステムのアーキテクチャが必要です。プロバイダーはインターフェイス IProvider を実装し、コンシューマーは IConsumer を実装する必要があります。実行中のアプリケーションは、IProvider と IConsumer のみを認識する必要があります。コンシューマーの実装は、InterfaceX を実装して List を取得するプロバイダーを (ServiceProcessor を使用して) 実行中のアセンブリに問い合わせることができます。これらの IProvider オブジェクトは、InterfaceX が定義するいくつかのイベントにコンシューマーをフックできるように (コンシューマー内で) InterfaceX にキャストする必要があります。これは、実行中のアセンブリがこの InterfaceX 型を認識していない (キャストが失敗する) ため、失敗します。解決策は、プラグインと実行中のアセンブリの両方が参照するアセンブリに InterfaceX を含めることですが、これは新しいプロバイダー/コンシューマーのペアごとに再コンパイルする必要があり、非常に望ましくありません。
助言がありますか?
長いバージョン:
より高いレベルの再利用性を実現するためにプラグインを使用する、ある種の汎用サービスを開発しています。このサービスは、プロバイダーとコンシューマーを使用したある種のオブザーバー パターン実装で構成されています。プロバイダーとコンシューマーの両方が、メイン アプリケーションのプラグインである必要があります。最初に、ソリューションに含まれているプロジェクトをリストして、サービスがどのように機能するかを説明しましょう。
プロジェクト A: すべてのプラグインと基本機能をホストする Windows サービス プロジェクト。デバッグを容易にするために、TestGUI Windows Forms プロジェクトが使用されます。プロジェクト B の ServiceProcessor クラスのインスタンスは、プラグイン関連の作業を行っています。このプロジェクトのサブフォルダー "Consumers" と "Providers" にはサブフォルダーが含まれており、各サブフォルダーにはそれぞれコンシューマーまたはプロバイダーのプラグイン アセンブリが含まれています。
プロジェクト B: ServiceProcessor クラス (すべてのプラグインのロードとプラグイン間のディスパッチなどを行う)、IConsumer および IProvider を保持するクラス ライブラリ。
プロジェクト C: プロジェクト B にリンクされたクラス ライブラリで、TestConsumer (IConsumer を実装) と TestProvider (IProvider を実装) で構成されます。追加のインターフェイス (ITest、それ自体は IProvider から派生) は、TestProvider によって実装されます。
ここでの目標は、Consumer プラグインが ServiceProcessor に (少なくとも IProvider を実装する) プロバイダーを問い合わせることができるようにすることです。返された IProvider オブジェクトは、コンシューマーがイベント ハンドラーを ITest イベントにフックできるように、IConsumer 実装で実装する他のインターフェイス (ITest) にキャストする必要があります。
プロジェクト A が開始されると、コンシューマー プラグインとプロバイダー プラグインを含むサブフォルダーが読み込まれます。以下は、これまでに遭遇し、解決しようとしたいくつかの問題です。
これは、TestProvider と TestConsumer が認識しているメソッドとイベントにのみ適用されるため、プロジェクト C に常駐していたインターフェイス ITest です。一般的な考え方は、プロジェクト A をシンプルに保ち、プラグインが互いに何をするかを意識しないことです。
プロジェクト C の ITest と、IProvider を ITest にキャストする TestConsumer の Initialize メソッドのコード (ITest を実装するオブジェクトが IConsumer オブジェクトとして知られている場合、単一のクラス ライブラリ自体で失敗することはありません) を使用すると、無効なキャスト エラーが発生します。 . このエラーは、プロジェクト A からも参照されるプロジェクト B に ITest インターフェイスを配置することで解決できます。ただし、新しいインターフェイスをビルドするときにプロジェクト A を再コンパイルする必要があるため、これは非常に望ましくありません。
プロバイダーとコンシューマーのみがこのインターフェイスを認識する必要があるため、プロジェクト C のみによって参照される単一のクラス ライブラリに ITest を配置しようとしましたが、成功しませんでした。プラグインをロードすると、CLR は参照されたプロジェクトが見つからないと述べています。これは、現在の AppDomain の AssemblyResolve イベントにフックすることで解決できますが、どういうわけかこれも望ましくないようです。ITest は再びプロジェクト B に戻りました。
プロジェクト C をコンシューマーとプロバイダー用の別のプロジェクトに分割しようとしましたが、どちらもそれ自体がうまく機能するアセンブリを読み込んでいます。両方のアセンブリは、Assemblies コレクションまたは現在の AppDomain に常駐しています。 、Version=1.0.0.0、Culture=neutral、PublicKeyToken=2813de212e2efcd3 アセンブリが見つかりました: Datamex.Projects.Polaris.Testing.Consumers、Version=1.0.0.0、Culture=neutral、PublicKeyToken=ea5901de8cdcb258
コンシューマーはプロバイダーを使用するため、コンシューマーからプロバイダーへの参照が行われました。ここで、AssemblyResolve イベントが再び発生し、次のファイルが必要であることが示されました。
私の質問: これはなぜですか? このファイルはすでにロードされていますよね?IProvider から、実装がわかっているインターフェイスへのキャストが不可能なのはなぜですか? これはおそらく実行中のプログラム自身がこのインターフェースを知らないためだと思いますが、これを動的にロードすることはできないのでしょうか?
私の最終的な目標: コンシューマー プラグインは、Interface x を実装しているプロバイダーを ServiceProcessor に問い合わせます。プロバイダーは、インターフェイス x を認識してアセンブリを実行せずに、このインターフェイス x にキャストできます。
助けてくれる人?
前もってありがとう、エリック