5

バックグラウンド:

MEFを使用して、.NET 4.0でC#を使用するWinFormアプリケーションにプラグインアーキテクチャを提供することに興味がありますが、いくつかの点について明確ではありません。

まず、私はまだC#で​​DLLを構築する作業をまったく行っていません。また、DLLアセンブリの概念と、DLLが通常どのようにメモリにロードされるか(つまり、必要に応じて一度にまたは分割して)について少し曖昧です。

意図:

プログラムはマシンハードウェア制御フレームワークであり、基本的なツールバーやメニューなどを備えた汎用環境であるプライマリWinForm GUIで構成されますが、バルクGUIコンテンツは含まれません。(考えてみてください:MDI親ですが、実際にはそうではありません)。

プラグインは、特定のマシンのすべてのコントロールを提供します。多くの可能なプラグインのそれぞれには、潜在的に30〜50の大きなUserControlが含まれ、それぞれに数十のWinFormコントロールと、さまざまなマシンコントロールパネルを構成する大量のサポートコードが組み込まれています。

つまり、メインプログラムは軽量の一般的なフレームワークであり、プラグインには、多くのアイコン、画像、その他のリソースなど、メインプログラムのユーザーインターフェイスに表示されるGUIコントロールと機能の大部分が含まれています。これにより、プラグインDLLが非常に大きくなる可能性があります。

目標は、ユーザーがメニューからプラグインを選択できるようにすることです。次に、選択時にプラグインをロードして実行します。これにより、ほとんど空のメインGUIにパネル、メニュー、およびツールボックスが大量に表示されます。

これを行うには、最初に各プラグインからメタデータを抽出して、プログラムの初期メニューにデータを入力する必要があります。これには、プラグインのタイトル、説明、アイコン、バージョン番号、およびその他の情報が含まれます。

質問は次のとおりです。

MEFを使用して、プラグインフォルダーに格納されている多数の大きなDLLのそれぞれからメタデータを読み取ろうとすると、メタデータ値にアクセスする前にDLL全体がメモリにコピーされますか?

もしそうなら、各DLLファイルを開き、メタデータをメモリに読み込んで初期メニューを作成する方法はありますか?その後、選択した完全なDLLをMEFからロードしますか?

MEFを介してプラグインを読み取るための一般的なDirectoryCatalogおよびAggregateCatalogテンプレートは、検出されたすべてのDLLをメモリにコピーし、カタログコレクションに格納すると想定しています。

DLLには1つの連続したコードブロック(アセンブリ)が含まれていますか、それとも必要に応じて個別にインデックスが作成されてメモリにコピーされる複数の個別のブロック(複数のアセンブリ)が含まれていますか?

私はおそらく基本を理解しておらず、おそらく紛らわしい用語です。MEF、DLL、およびアセンブリ全般のロード動作についての洞察をいただければ幸いです。ありがとう !

4

1 に答える 1

5

MEFを使用して、プラグインフォルダーに格納されている多数の大きなDLLのそれぞれからメタデータを読み取ろうとすると、メタデータ値にアクセスする前にDLL全体がメモリにコピーされますか?

私の知る限り、DLL全体がメモリにロードされます。ただし、これはMEFとは何の関係もありません。Assembly.Loadの呼び出しを使用してDirectoryCatalog、アセンブリを(を介して)ロードします。このメソッドはMEFの一部ではありませんが、.NETFrameworkのコアメソッドです。ロードされたアセンブリのほとんどは、この方法でロードされます。Process Explorerを使用してアプリケーションを実行しているプロセスを監視すると、ロードされたアセンブリのサイズによって仮想サイズが増加することがわかります。したがって、巨大なアセンブリをロードすると、プロセスの仮想サイズが大きくなります。AssemblyCatalog

もしそうなら、各DLLファイルを開き、メタデータをメモリに読み込んで初期メニューを作成する方法はありますか?その後、選択した完全なDLLをMEFからロードしますか?

これを行う方法があります。

1つの方法は、新しいアプリケーションドメインを作成CompositionContainerし、新しいAppDomainにを作成して、検出された部分を確認することです。次に、これらのパーツに関する情報をメインのAppDomainにシリアル化します。最後に、新しいAppDomainをアンロードします。次に、本当に必要なパーツを確認し、それらを含むアセンブリのみをロードできます。これを行う方法の例は、この回答にあります。

もう1つのアプローチは、Mono.Cecilを使用することです。これは、アセンブリをロードせずに検査するのに役立つ優れたライブラリです。次のような方法で、MEFのメタデータのエクスポートと組み合わせることができます。

public static bool IncludesTypeWithSpecificExportMetadata<T>(string assemblyPath, string name, T value)
    {
        AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath);

        bool typeWasFound = false;          

        foreach (TypeDefinition typeDefinition in assemblyDefinition.MainModule.GetTypes())
        {
            foreach (CustomAttribute customAttribute in typeDefinition.CustomAttributes)
            {
                if (customAttribute.AttributeType.FullName == typeof(ExportMetadataAttribute).FullName)
                {
                    string actualName = (string)customAttribute.ConstructorArguments[0].Value;
                    T actualValue = (T)((CustomAttributeArgument)customAttribute.ConstructorArguments[1].Value).Value;
                    if (actualName.Equals(name) && actualValue.Equals(value))                        
                    {
                        typeWasFound = true;                       
                    }
                }
            }
        }

        return typeWasFound;
    }

アセンブリファイルのパスと名前/値のペアが与えられると、このメソッドはMono.Cecilを使用してアセンブリを検査し、ExportMetadataAttributeで装飾された同じ名前/値のペアを持つタイプを探します。

MEFを介してプラグインを読み取るための一般的なDirectoryCatalogおよびAggregateCatalogテンプレートは、検出されたすべてのDLLをメモリにコピーし、カタログコレクションに格納すると想定しています。

本当です。

DLLには1つの連続したコードブロック(アセンブリ)が含まれていますか、それとも必要に応じて個別にインデックスが作成されてメモリにコピーされる複数の個別のブロック(複数のアセンブリ)が含まれていますか?

これについてはわかりません。答えは、DonBoxの「Essential.NETVolume 1」、またはJeffrey Richterの「C#viaCLR」にあります。

私はおそらく基本を理解しておらず、おそらく紛らわしい用語です。MEF、DLL、およびアセンブリ全般のロード動作についての洞察をいただければ幸いです。ありがとう !

私が上で述べた本には、アセンブリがどのように解決/ロードされるかが詳細に含まれています。SuzanneCookのブログもご覧ください。

さて、お聞きしたいのですが。本当に大きなファイルをアセンブリに埋め込む必要がありますか?別の方法を見つけることができれば、これは必要ありません。プラグインエンジンは少しシンプルになります。

最後に、Microsoftのスマートクライアントソフトウェアファクトリーをご覧になることをお勧めします。それはあなたが言及するほとんどすべてを行うことができます。それを理解し、快適に感じるにはある程度の努力が必要ですが、長期的には、おそらく時間の負荷を節約できます。

于 2013-02-02T15:12:10.730 に答える