How to manage discovery and composition as 2 separate concerns?

后端 未结 2 1810
野的像风
野的像风 2021-01-27 09:52

I have set up an assembly catalog:

  private CompositionContainer GetContainer() {
     // initialize directory info
     ExtensionDirectory = new DirectoryInfo(         


        
相关标签:
2条回答
  • 2021-01-27 10:08

    I think these concerns are already separated: discovery is handled by catalogs, and composition is done by export providers.

    In the typical case, you just pass a catalog directly to the container and for convenience it will automatically take care of creating an CatalogExportProvider for it.

    But you can also create one or more export providers yourself and pass them to the container with this constructor overload. (You may also have to set the SourceProvider to point back at the container after that, so that the export providers can use each other.)

    You can create your own ExportProvider implementations, and they don't even have to be backed by catalogs.

    0 讨论(0)
  • 2021-01-27 10:26

    In order to satisfy the requirements, I created 3 classes:

    public sealed class CompositionFactory {
      [Import("Provider")]
      private IProvider importProvider;
    
      /* MEF initialization */
    }
    
    [Export("Provider")]
    public sealed class AssemblyProvider : IProvider {
      private CatalogExportProvider _provider;
    }
    
    internal sealed class ComposableAggregate { }
    

    The CompositionFactory initializes MEF to discover the AssemblyProvider. When the provider initializes:

    private CatalogExportProvider InitializeProvider() {
       // directory catalog
       var dirCatalog = new DirectoryCatalog(ExtensionDirectory.FullName);
       return new CatalogExportProvider(dirCatalog);
    }
    

    ...we return a CatalogExportProvider. I can now use an API to the CompositionFactory:

    public ISomething GetSomething(string ContractName, object ContractParam) {
       // implementation
    }
    

    ...to query for the correct composable part using a contract name:

    public ComposablePartDefinition GetPartDefinition(string ContractName) {
       return _provider.Catalog.Parts
                       .Where(p => p.ExportDefinitions
                                    .Select(e => e.ContractName)
                                    .Any(c => c == ContractName))
                       .FirstOrDefault();
    }
    

    The work is then completed in the ComposableAggregate helper class:

    internal ISomething Value {
       get {
          return _container.GetExport<IEntity>(_contractName).Value;
       }
    }
    
    private CompositionBatch CreateBatch() {
       CompositionBatch batch = new CompositionBatch();
       // create composable part from definition
       ComposablePart importDef = CreatePart(_contractName);
       batch.AddPart(importDef);
       return batch;
    }
    
    private ComposablePart CreatePart(string ContractName) {
       // get part definition from catalog
       return _provider.GetPartDefinition(ContractName).CreatePart();
    }
    
    0 讨论(0)
提交回复
热议问题