2012-10-18 30 views
5

私のアプリケーションは、いくつかのコアアセンブリといくつかの拡張/プラグインアセンブリで構成されています。 MEFがプラグインが提供しなければならないすべての部分を知るためには、私は決して部品を使用しない場合でも、これらのアセンブリをロードする必要があります。これにより、起動時にアプリケーションを起動する時間が長くなります(起動時にすべてのアセンブリをロードする場合)。また、メモリの占有量も増加します。アセンブリ/カタログの遅延読み込み

理想的には、アセンブリを実際に必要とするまで、アセンブリをロードする必要はありません。私はプラグインのエクスポートデータのみを読み込み、実際に部品をインポートする必要があるときは、アセンブリをロードして部品を提供します。

私が書いたことはほとんどありませんが、MEF CachedAssemblyCatalog - Lazy Loading of Assembliesで質問したところ、このコードは安定したものではなく、MEFチームによって維持管理されていないことに気付きました。それを使用しないことにしました。彼らの全体のアセンブリをロードせずにプラグインアセンブリの輸出メタデータにアクセスすることができること

  • 私の質問は、私は、この動作を達成することができますどのようにしてあります。

  • パーツをインポートするコードとの透過的な統合。すなわち、通常通り輸入を使用する - 他の誰か(専門カタログ?)は、必要に応じてアセンブリを積み込み、要求された部分を提供する。
  • はなど再構成、怠惰なタイプ、

として、既存のMEFの機能を失っていない私は、メタデータのアセンブリ、XMLファイルやその他もろもろを作成するには、事前にプラグインを解析する必要が溶液で完全に大丈夫ですよ。

答えて

2

アセンブリの読み込みが遅れた直後の場合は、ソリューションの一部をthis questionに使用する可能性があります。そのソリューションで取得されたすべての情報を取得する必要はありません。おそらく、契約名、アセンブリ名、およびその部分が契約の輸出または輸入を行っているかどうかだけです。あなたがそれらを必要として、あなたは、このような場合のために、アセンブリをロードするカタログを書くことができます:

あなたはDelayLoadCatalogはとしては非常にスマートではありません。この

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; 
    } 
} 

のような例を使用することができます

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(); 
     } 
    } 
} 

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

+0

こんにちはペトリック、おかげさまで大変助かりました!私は少し前にリンクした質問に遭遇し、この問題を解決することで多くの助けになりました。私がやったことは、そこに書いたものと似たものでした。データをファイルにシリアライズし、そのファイルを使用する新しいカタログを作成しました。このようにして、メタデータを含むすべてのエクスポートが利用可能になり、 'ReflectionModelServices' APIを使用して、すべてが遅延ロードされました。これは私の要件を満たす最善の方法のようです。私は、私がやったことでこの質問に自分自身で答える時間があることを願っています。再度、感謝します! –

0

私は自分自身で解決策を実装し、最近GitHubで利用できるようにしました。 LazyAssemblyLoadingソリューションを使用すると、アセンブリのパーツ情報をシリアル化し、後でそのコンポーネントを使用してLazyAssemblyCatalogを初期化することができます。アセンブリの一部が実際に必要な場合にのみアセンブリをロードします。ロードされる。

関連する問題