5

私のアプリケーションは、いくつかのコア アセンブリといくつかの拡張/プラグイン アセンブリで構成されています。プラグインが提供するすべてのパーツを MEF が認識できるようにするには、アセンブリのパーツをまったく使用しない場合でも、これらのアセンブリを読み込む必要があります。これにより、アプリケーションの起動に時間がかかり (起動時にすべてのアセンブリをロードする場合)、メモリ フットプリントも増加します。

理想的には、実際に必要になるまでアセンブリをロードする必要はありません。プラグインのエクスポート データのみをロードし、実際にパーツをインポートする必要がある場合は、MEF がアセンブリをロードしてパーツを提供します。

私が書いたほぼすべてのことを実行するものがあることがわかりましたが、 MEF CachedAssemblyCatalog - Lazy Loading of Assembliesでそれについて尋ねた後、このコードは安定しているとは見なされず、MEF チームによって維持されていないことに気付きました。使用しないことにしました。

私の質問は、どうすればこの動作を達成できるかです:

  • アセンブリ全体をロードせずに、プラグイン アセンブリのエクスポート メタデータにアクセスできる。
  • パーツをインポートするコードとの透過的な統合。つまり、通常どおりインポートを使用します。必要に応じて、他の誰か (特殊なカタログ?) がアセンブリをロードし、要求されたパーツを提供します。
  • 再構成、遅延型などの既存の MEF 機能を失うことはありません。

プラグインを事前に解析して、メタデータ アセンブリ、XML ファイルなどを作成する必要があるソリューションにはまったく問題ありません。

4

2 に答える 2

2

アセンブリの読み込みを遅らせた直後であれば、この質問に対する解決策の一部を使用できる可能性があります。そのソリューションで取得されるすべての情報を取得する必要はありません。おそらく、コントラクト名、アセンブリ名、およびパーツがコントラクトをエクスポートしているかインポートしているかだけです。次に、たとえば次のように、必要に応じてアセンブリをロードするカタログを作成できます。

public sealed class DelayLoadingCatalog : ComposablePartCatalog
{
    // List containing tuples which have the 'contract name' 
    // and the 'assembly name'
    private readonly List<Tuple<string, string>> m_Plugins 
        = new List<Tuple<string, string>>();
    private readonly Dictionary<string, AssemblyCatalog> m_Catalogs 
        = new Dictionary<string, AssemblyCatalog>();

    public DelayLoadingCatalog(IEnumerable<Tuple<string, string>> plugins)
    {
        m_Plugins.AddRange(plugins);
    }

    public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
    {
        var partsToLoad = m_Plugins
            .Where(t => t.Item1.Equals(definition.ContractName));
        foreach (var part in partsToLoad)
        {
            if (!m_Catalogs.ContainsKey(part.Item2.Name))
            {
                var assembly = Assembly.Load(new AssemblyName(part.Item2.Name));
                m_Catalogs.Add(part.Item2.Name, new AssemblyCatalog(assembly));
            }
        }

        return m_Catalogs.SelectMany(p => p.Value.GetExports(definition));
    }

    public override IQueryable<ComposablePartDefinition> Parts
    {
        get 
        { 
            throw new NotImplementedException(); 
        }
    }
}

その後、このように使用できます

class Program
{
    public void Init()
    {
        var domainSetup = new AppDomainSetup
        {
            ApplicationBase = Directory.GetCurrentDirectory(),
        };

        var scanDomain = AppDomain.CreateDomain(
            "scanDomain", 
            null, 
            domainSetup);
        var scanner = scanDomain.CreateInstanceAndUnwrap(
            typeof(MyScanner).Assembly.FullName, 
            typeof(MyScanner).FullName) as MyScanner;
        var plugins = scanner.Scan(myPluginsPath);

        // Make sure we don't have the assemblies loaded anymore ...
        AppDomain.Unload(scanDomain);

        var catalog = new DelayLoadingCatalog(plugins);
        var container = new CompositionContainer(catalog);

        container.ComposeParts(this);
    }

    [Import("MyCoolExport")]
    public object MyImport
    {
        get;
        set;
    }
}

例の DelayLoadCatalog は、タプルのリストを検索し続けるため、あまりスマートではありません。ただし、コードの最適化はそれほど難しくありません。ただし、たとえば、すべてのアセンブリが読み込まれたかどうかを確認し、その時点でそのリストの検索を停止することができます。

于 2013-01-21T22:33:12.177 に答える
0

誰かが興味を持っている場合は、私が自分でソリューションを実装し、最近 GitHub で利用できるようにしました。LazyAssemblyLoadingソリューションを使用すると、ユーザーはアセンブリのパーツ情報をシリアル化し、後でそれを使用して を初期化できます。これLazyAssemblyCatalogにより、パーツの 1 つが実際に必要な場合にのみアセンブリが読み込まれ、アセンブリが読み込まれていない間は通常どおりメタデータを使用できます。 .

于 2016-09-21T20:25:55.247 に答える