使用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);

我不想从零件端导入任何东西。

可以找到一个示例项目(带有无参数的构造函数)here

最佳答案

当MEF看到类型为ExportFactory<IFoo>的导入时,它将以特殊方式对其进行处理。它不是从字面上寻找ExportFactory<IFoo>导出,而是寻找IFoo导出,并神奇地为该类型生成了一个工厂。

您的错误是,您希望此魔术也可以自动替代您自己称为ExportFactorySrviceProviderFactory的替代方法。这不是真的。当您在某处导入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现在支持导出开放的通用类型。

这就是I already suggested you export Func instead的原因,但显然您不喜欢该答案。

您也可以尝试复制ExportFactory魔术。这是可能的,但是MEF的使用情况非常先进。如果您想这样做,我建议您看一下ExportFactoryProvider的MEF源代码,以了解如何构建支持参数的自己的实现。

09-27 06:59