2011-12-14 28 views
1

私は自分のカスタムExportProviderでどのようにインポートを持つことができるか知っています。私がやろうとしていることの例です:カスタムExportProviderのインポートを受け入れる

public class MyExportProvider : ExportProvider 
{ 
    private List<Export> _exports; 

    [Import()] 
    private IConfig _config; 

    public MyExportProvider() 
     base() 
    { 
     _exports = new List<Export>(); 
    } 

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, 
                  AtomicComposition composition) 
    { 
     if (!_exports.Any()) 
      Initialize(); 

     return _exports.Where(x => definition.IsConstraintSatisfiedBy(s.Definition); 
    } 

    private void Initialize() 
    { 
     var contractName = typeof(MyObject).FullName; 

     var exportDefinition = new ExportDefinition(contractName, null); 
     var export = new Export(exportDefinition,() => new MyObject(_config)); 

     _exports.Add(export); 
    } 
} 

私はCompositionContainerを作成するときにプロバイダを追加しています。

残念ながら、インポートは決して満たされません。 AllowDefaults = trueを設定してプロバイダを作成することができますが、_configは常にnullです。

インポートが完了するようにコンテナおよび/またはプロバイダを設定するにはどうすればよいですか?

+0

逆投票できません。しかし、あなたはそれが編集されているので、自分でそれを行うことができます(はい、私は別の答えについて話しています) – NullUserException

答えて

2

エクスポートプロバイダを追加するときは、まだコンポジションコンテナを作成しています。したがって、まだ作成されていないコンポジションコンテナを使用してカスタムエクスポートプロバイダの一部をインポートする方法はわかりません。

私はまず、MyExportProviderの作成に使用される一時的なCompositionContainerを作成します。

その後、MyExportProviderを使用して、残りのアプリケーションで使用される2番目の最終CompositionContainerを作成します。

EDIT:あなたはまた、別の角度から問題を検討するかもしれない

// this is your real container, only shown here for reference 
    CompositionContainer container; 

    public void BootstrapContainerMethod() 
    {   
     // Replace this part with the catalogs required to create your export provider. 
     var catalog = new AggregateCatalog(); 
     catalog.Catalogs.Add(new DirectoryCatalog("./bin", "*.dll")); 

     // Your temporary container, declared here in local scope 
     // will be disposed because of using 
     using (var bootstrapContainer = new CompositionContainer(catalog)) 
     { 
      var myExportProvider = bootstrapContainer.GetExportedValue<IMyExportProvider>(); 

      // create your real container and optionnally add catalogs (not shown here) 
      container = new CompositionContainer(myExportProvider); 
     } 
    } 

。あなたは本当にあなたのカスタムExportProviderでインポートを持っている必要がありますか?私はあなたの要件を知らないが、おそらくあなたは輸入を持たずに行うことができます。

+0

このようなネストされたコンテナを持つパフォーマンスやメモリに関する懸念はありますか? – SonOfPirate

+0

入れ子のコンテナは使用しません。例を使用して回答を編集します。 – Gilles

+0

しかし、MEFは「発見」プロセスを2回通らなければならないという意味ではありませんか? – SonOfPirate

1

解決策2つのソリューションの代わりに、単一のエクスポートプロバイダでこれを結び、同じコンテナを使用して自身を作成することができます。例として、私は次の契約を定義して、それは輸出だ:

public interface ILogger 
{ 
    void Log(string message); 
} 

[Export(typeof(ILogger))] 
public class ConsoleLogger : ILogger 
{ 
    public void Log(string message) 
    { 
     Console.WriteLine(message); 
    } 
} 

そして、私の例ExportProviderで、私はそれのインスタンスをインポートできることを期待:

public class TestExportProvider : ExportProvider 
{ 
    private readonly object _lock = new object(); 
    private bool _initialised; 

    [Import] 
    public ILogger Logger { get; set; } 

    public void SetCompositionService(ICompositionService service) 
    { 
     if (service == null) throw new ArgumentNullException("service"); 

     lock (_lock) 
     { 
      if (!_initialised) 
      { 
       InitialiseProvider(service); 
      } 
     } 
    } 

    private void InitialiseProvider(ICompositionService service) 
    { 
     service.SatisfyImportsOnce(this); 
     _initialised = true; 
    } 

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) 
    { 
     if (_initialised) 
     { 
      Logger.Log("Getting available exports for '" + definition.ContractName + "'"); 

      // Do work here.); 
      return Enumerable.Empty<Export>(); 
     } 

     return Enumerable.Empty<Export>(); 
    } 
} 

私が提供しますたとえばICompositionServiceCompositionContainerが実装されており、私がSetCompositionServiceに電話すると、最初の初期化が実行されます。それはすでに初期化されているかどうかをチェックし、そうでなければ、SatisfyImportsOnceメソッドを呼び出します。

私たちは、このような何かこれを配線します:

// Build our catalog. 
var catalog = new AssemblyCatalog(typeof(Program).Assembly); 

// Create our provider. 
var provider = new TestExportProvider(); 

// Create our container. 
var container = new CompositionContainer(catalog, provider); 

// Register the composition service to satisfy it's own imports. 
provider.SetCompositionService(container); 

明らかにあなたはどんな輸入を使用することはできないだろうし、あなたのExportProviderが明示的にあなたのため作成されますが、他のすべてのために、それが動作するはずですが。

関連する問題