分離されたPluginAPIDLL
まず、PluginAPI(インターフェースを含む)は、メインアプリケーションとは別のDLLである必要があります。メインアプリケーションはPluginAPIを参照し、各プラグインはPluginAPIを参照します。あなたはおそらくすでにこれを行っています。
インターフェイスのバージョン管理
次に、構造的には、新しいプロパティまたはメソッドを追加するたびに新しいインターフェイスを作成する必要があります。
例えば:
- バージョン1:Plugins.IPerson
- バージョン2:Plugins.V2.IPerson:Plugins.IPerson
- バージョン3:Plugins.V3.IPerson:Plugins.V2.IPerson
APIを削除または完全に再設計することを決定したまれなケースでは、例:
- バージョン4:Plugins.V4.IPerson//インターフェイスの継承なし
分離されたPluginAPIDLLのバージョン管理
最後に、このインターフェイスバージョニングの構造アーキテクチャを使用しても、PluginAPI.dllのバージョニングがどのように行われるかは100%わかりません。それはうまくいくかもしれません
また
バージョンごとに一致するdllが必要になる場合があります(それぞれが前のバージョンを参照しています)。これが事実であると仮定します。
ケース3の解決策
それでは、プラグインよりも古いメインプログラムであるケース[3]を見てみましょう。
- Person Pluginは、Plugins.V2.IPluginを実装し、V3 .dllを参照します(面白くするため)。
- メインプログラムはV1.dllを参照します
- プラグインフォルダには、V2およびV3プラグインの.dllが含まれます。
- メインアプリフォルダーには、V1プラグイン.dll(他のファイルの中でも)のみが含まれます
- メインアプリは、IPersonインターフェースのV1定義を介してPersonプラグインと参照を見つけてロードします
- もちろん、プラグインからメインアプリにアクセスできるのはV1メソッドとプロパティのみです。
- (追加のメソッドは、リフレクションを介してアクセスできます-あなたが望むことではありません)
ボーナスアップデート
プラグインを使用する可能性がある場合
- システムを拡張するサードパーティ。それがオプションである場合、またはWebベースの場合は、ソースコードをURLにリダイレクトする方がよいでしょう。これは多くのソフトウェアプロジェクトにとっての夢ですが、プラグインフレームワークを構築するための追加の作業を行う前に、関心のあるサードパーティパートナーができるまで待つ必要があります。
- ユーザーが編集可能な「スクリプト」。独自のスクリプト言語を構築するのではなく、非常に制限的な(リフレクションなどを無効にする)appdomainの制限的なインターフェイスに対してユーザーc#コードをコンパイルする必要があります。
- セキュリティのグループ化-コアソフトウェアはトラステッドプラットフォームコールを使用する場合があります。よりリスクの高いモジュールは、別のライブラリに分離し、オプションでエンドユーザーが除外できます。
プラグインを使用しない場合
私はless-is-moreの支持者です。オーバーエンジニアリングしないでください。優れたモジュラーソフトウェアを構築している場合は、クラスと名前空間を使用してください(インターフェイスに夢中にならないでください)。「モジュラー」とは、SOLIDの原則を順守しようとしていることを意味しますが、プラグインアーキテクチャが必要であることを意味するわけではありません。制御の反転でさえ、多くの状況でやり過ぎです。
将来、サードパーティに公開する予定がある場合は、最初からプラグインアーキテクチャにしないでください。プラグインフレームワークは、後の段階で構築できます。i)インターフェイスを派生させます。ii)同じプロジェクト内のインターフェースを使用してプラグインを定義します。iii)プラグインローダークラスを使用して内部プラグインをロードします。iv)最後に、外部ライブラリローダーを実装できます。これらの4つのステップのそれぞれは、それ自体で動作するシステムを残し、完成したプラグインシステムに向かって移動します。
ホットスワップ可能なプラグイン
プラグインアーキテクチャを設計するとき、プラグインをホットスワップ可能にすることができることを知りたいと思うかもしれません。
メモリを解放せずに-新しいプラグインをロードし続けるだけです。i)再起動せずに非常に長時間実行することを期待しているサーバーソフトウェアの場合を除いて、これは通常は問題ありません。そしてii)その間に多くのプラグインの変更とアップグレードを期待します。実行時にプラグインをロードすると、アセンブリがメモリにロードされ、アンロードできません。理由については[2]を参照してください。
メモリを解放すると-AppDomainをアンロードできます。AppDomainは同じプロセスで実行されますが、参照が分離されています。オブジェクトを直接参照したり呼び出したりすることはできません。代わりに、呼び出しをマーシャリングし、データをアプリドメイン間でシリアル化する必要があります。プラグインを頻繁に変更しない場合、追加された複雑さは価値がありません。i)マーシャリング/シリアル化によるパフォーマンスの低下、ii)コーディングの複雑さの大幅な増加(イベントとデリゲートおよびメソッドを単純に使用することはできません)通常どおり)、iii)これはすべて、より多くのバグにつながり、デバッグをより困難にします。
したがって、オプション[2]に興味がある場合は、最初に[1]を試して、[2]に必要な問題が発生するまでそのアーキテクチャを使用してください。過度に設計しないでください。私を信じてください。私は大学時代に[2]アーキテクチャを構築しました。それは楽しいですが、ほとんどの場合、やり過ぎで、プロジェクトを殺してしまう可能性があります(ビジネス以外の機能に多くの時間を費やします)。