Как управлять открытием и составлением как двумя отдельными задачами? - PullRequest
0 голосов
/ 09 марта 2012

Я настроил каталог сборок:

  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] s, то ни одна из частей не была бы включена в _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 ]

1 голос
/ 09 марта 2012

Я думаю, что эти проблемы уже разделены: обнаружение обрабатывается каталогами, а составление выполняется поставщиками экспорта.

В типичном случае вы просто передаете каталог непосредственно в контейнер, и для удобства он будетавтоматически позаботьтесь о создании для него CatalogExportProvider .

Но вы также можете создать одного или нескольких поставщиков экспорта и передать их в контейнер с перегрузкой этого конструктора .(Возможно, вам также придется установить SourceProvider , чтобы указывать на контейнер после этого, чтобы поставщики экспорта могли использовать друг друга.)

Вы можете создать свой собственный ExportProvider реализации, и они даже не должны быть подкреплены каталогами.

0 голосов
/ 15 марта 2012

Для удовлетворения требований я создал 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();
}
...