Пользовательская 'ExportFactory' - PullRequest
6 голосов
/ 11 декабря 2010

Настольное приложение, использующее MEF, импортирует множество «ServiceProviders». Каждая часть (ServiceProvider) является классом внутри отдельной DLL. Все библиотеки DLL находятся в папке «Plugin», которая используется настольным приложением.

Так как мне нужны были новые экземпляры моих частей, ExportFactory был лучшим выбором. Проблема в том, что мои детали имеют конструкторы. Мне нужно передать некоторые параметры в конструктор части, которая не поддерживается ExportFactory (MEF2, Preview2).

Мне нужно что-то вроде этого:

// Each part has its own dependency
Dependency dependency = LoadDependency(myPart.Metedata["Name"]);
// Injecting dependency into part's constructor
myPart.CreateExport(dependency);

Я не хочу импортировать что-либо с моей стороны.

Пример проекта (с конструктором без параметров) можно найти здесь .

1 Ответ

5 голосов
/ 12 декабря 2010

Когда MEF видит импорт типа ExportFactory<IFoo>, он обрабатывает это особым образом. Вместо буквального поиска экспорта ExportFactory<IFoo> он ищет экспорт IFoo и волшебным образом генерирует фабрику для этого типа.

Ваша ошибка в том, что вы ожидаете, что эта магия также автоматически сработает для вашей собственной альтернативы ExportFactory, которую вы назвали SrviceProviderFactory. Это неправда. Когда вы импортируете SrviceProviderFactory<IFoo,IFooMetadata> куда-то, MEF буквально ищет экспорт этого типа.

Простое решение - предоставить ему этот экспорт. Вручную экспортируйте фабрику для каждой реализации IServiceProvider. Например, если у вас есть FooServiceProvider:

public class FooServiceProvider : IServiceProvider
{
    public FooServiceProvider(Dependency dependency)
    {
        ...
    }
}

Тогда вам также нужно иметь FooServiceProviderFactory:

[Export(typeof(IServiceProviderFactory))]
[ExportMetaData("foo", "bar")]
public class FooServiceProviderFactory : IServiceProviderFactory
{
    public IServiceProvider CreateServiceProvider(Dependency d)
    {
       return new FooServiceProvider(d);
    }
}

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

public class FactoryUser
{
    [ImportMany]
    public Lazy<IServiceProviderFactory,IDictionary<string,object>>[] Factories 
    {
        get;
        set;
    }

    public void DoSomething()
    {
       var factory = Factories.First(x => x.Metadata["foo"] == "bar").Value;
       var serviceProvider = factory.CreateServiceProvider(someDependency);
       ...
    }
}

Раздражает то, что для каждой реализации поставщика услуг вам также необходимо создать и экспортировать реализацию фабрики. Вы можете сохранить работу, создав общий фабричный базовый класс (например, SrviceProviderFactory), но вам все равно придется извлекать определенные классы, потому что вы не можете использовать параметры универсального типа в экспортах MEF. обновление : Я считаю, что .NET 4.5 теперь поддерживает экспорт открытых универсальных типов.

Вот почему Я уже предлагал вам экспортировать Func вместо , но, видимо, вам не понравился этот ответ.

Вы также можете попытаться повторить магию ExportFactory. Это возможно, но очень продвинутый вариант использования MEF. Если вы хотите сделать это, я предлагаю вам взглянуть на источники MEF ExportFactoryProvider, чтобы узнать, как создать собственную реализацию с поддержкой параметров.

...