Переопределение композиции MEF - PullRequest
3 голосов
/ 02 марта 2012

Как я могу переопределить композицию MEF, чтобы, если импортирующий конструктор запрашивал единственную зависимость, и существует многократная реализация этой требуемой зависимости, это взяло бы реализацию (экспорт) с самым высоким приоритетом (метаданные)?

[Export(typeof(IService))]
[ExportMetadata("Priority", 1)]
public class Service1 : IService
{
}

[Export(typeof(IService))]
[ExportMetadata("Priority", 2)]
public class Service2 : IService
{
}

public interface IService
{
}

public class ServiceWithDependencies
{
    [ImportingConstructor]
    public ServiceWithDependencies(IService service)
    {

    }
}

ServiceWithDependencies обычно не выполняются, так как существует более одной реализации IService.Но я хотел бы изменить MEF (переопределить / перехватить что-то), чтобы он использовал метаданные приоритета и внедрил реализацию с наивысшим приоритетом в конструктор ServiceWithDependencies.

Редактировать 1

Я не хочу, чтобы MEF диктовал, как я делаю вещи.Я хочу, чтобы это было как можно больше невидимым.Кроме того, это для фреймворка, и у меня нет контроля над тем, как люди будут нуждаться в зависимостях.Мне нужно поддерживать базовый конструктор инъекций.Я знаю о [ImportMany], но этот вопрос как раз о внедрении конструктора.

Ответы [ 2 ]

2 голосов
/ 02 марта 2012

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

В наших приложениях мы используем это, чтобы дать наивысшийприоритет для деталей в папке plugins, затем для деталей в приложении exe и, наконец, для всех других библиотек.

edit : вот полный пример.

Во-первых, типы:

[Export(typeof(IService))]
public class Service1 : IService { }

[Export(typeof(IService))]
public class Service2 : IService { }

public interface IService { }

[Export]
public class ServiceWithDependency
{
    [ImportingConstructor]
    public ServiceWithDependency(IService service)
    {
    }
}

[Export]
public class ServiceWithMultipleDependencies
{
    [ImportingConstructor]
    public ServiceWithMultipleDependencies(
        [ImportMany] IEnumerable<IService> services)
    {
    }
}

А вот как вы можете настроить контейнер:

var priorityCatalog = new TypeCatalog(typeof(Service1));
var priorityProvider = new CatalogExportProvider(priorityCatalog);

var mainCatalog = new TypeCatalog(
    typeof(ServiceWithDependencies),
    typeof(ServiceWithMultipleDependencies),
    typeof(Service2));
var mainProvider = new CatalogExportProvider(mainCatalog);

// priorityProvider gets priority because it is first
var container = new CompositionContainer(
    priorityProvider, mainProvider);
priorityProvider.SourceProvider = container;
mainProvider.SourceProvider = container;

// will get constructed with Service1
var foo = container.GetExportedValue<ServiceWithDependency>();

// will get constructed with both, proving that both are available
var bar = container.GetExportedValue<ServiceWithMultipleDependencies>();
1 голос
/ 02 марта 2012

проще всего было бы [ImportMany] и позволить выбрать тот, который имеет самые высокие метаданные. <- Это то, что мы делаем в наших проектах. </p>

Больше информации о том, что вы можете сделать - вы найдете здесь .

public class ServiceWithDependencies
{
    [ImportingConstructor]
    public ServiceWithDependencies([ImportManyAttribute]IEnumerable<Lazy<IService, IServiceMetadata>> services)
    {
       this._TheServiceIWant = services.Max(x=>x.Metadata.Prio).First().Instance;
    }
}

ps: код написан от руки, поэтому linq не будет прав - возможно,

EDIT:

вместо непосредственного управления службами в вашем классе, вы также можете импортировать и фабрику, которая имеет несколько методов, таких как:

 MyPluginFac.GiveServiceWithHighestPrio();
 MyPluginFac.GiveServiceWithPrio(1);
 ...

public class ServiceWithDependencies
{
    [ImportingConstructor]
    public ServiceWithDependencies(IServiceFac serviceFac)
    {
       this._TheServiceIWant = serviceFac.GiveServiceWithHighestPrio();
    }
}
...