如何将发现和构成作为两个独立的问题进行管理?

时间:2012-03-08 22:45:35

标签: c# .net mef composition

我已经设置了一个程序集目录:

  private CompositionContainer GetContainer() {
     // initialize directory info
     ExtensionDirectory = new DirectoryInfo(settings.ExtensionsPath);
     // directory catalog
     var dirCatalog = new DirectoryCatalog(ExtensionDirectory.FullName);

     return new CompositionContainer(dirCatalog);
  }

容器的内容将按预期加载目录中的所有程序集。我不想实际编写任何东西,因为我的构造函数会注入依赖项。

我想要做的是使用AssemblyCatalog作为存储库;查询特定导出,传递构造函数依赖项,然后仅编写 此过程中涉及的部分。

根据我的理解,如果我打电话

_container.ComposeParts(this);

...没有为[ImportingConstructor]提供导出,则_container中不会包含任何部分。

为了便于查询容器,我有一个方法如下:

  public Lazy<IEntity> GetPart(Func<Lazy<IEntity, IEntityMetaData>, bool> selector) {
     var entity = _container.GetExports<IEntity, IEntityMetaData>()
                            .Where(selector)
                            .Select(e => e as Lazy<IEntity>)
                            .FirstOrDefault();

     return entity; // this will be passed up to the composition service
  }

如果满足依赖关系的部分未包含在容器中,GetExports<T, M>()似乎不会返回包含[ImportingConstructor]的导出。

我的方法是将扩展容器/目录放在较低的水平;更高级别的合成服务将接收所有部分并组成最终对象。我决定使用这种方法,以便我们能够添加/扩展将来可用的目录类型。

2 个答案:

答案 0 :(得分:1)

我认为这些问题已经分开:发现由目录处理,组成由出口提供商完成。

在典型情况下,您只需将目录直接传递给容器,为方便起见,它会自动为其创建CatalogExportProvider

但您也可以自己创建一个或多个导出提供程序,并使用this constructor overload将它们传递给容器。 (在此之后,您可能还必须将SourceProvider设置为指向容器,以便导出提供程序可以相互使用。)

您可以创建自己的ExportProvider实现,甚至不必由目录支持。

答案 1 :(得分:0)

为了满足要求,我创建了3个类:

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

CompositionFactory初始化MEF以发现AssemblyProvider。提供者初始化时:

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

...我们返回CatalogExportProvider。我现在可以使用API​​到CompositionFactory:

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

...使用合同名称查询正确的可组合零件:

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

然后在ComposableAggregate帮助程序类中完成工作:

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