2012-03-02 82 views
3

如何覆盖MEF组合,以便如果导入构造函数要求单个依赖项,并且此需要的依赖项有多个实现,则需要具有最高优先级(元数据)的实现(导出)?覆盖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

而不是把重点中继资料的部分,你也可以把它们放在不同的目录,然后prioritize the catalogs

在我们的应用中,我们利用这个最优先零件在plugins文件夹,然后在应用程序EXE的部分,最后所有的其他库。

编辑:这是一个完整的示例。

一,类型:

[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>(); 
+0

对不起,如果我很慢,但我不明白这可以帮助构造函数注入。 – W3Max 2012-03-02 14:31:59

+0

与构造函数注入没有冲突,我们也使用它。 – 2012-03-02 15:15:09

+0

我没有说有问题,我只是说我不明白它是如何工作的。对不起,但我是MEF世界的新手。你能解释一下上面的例子吗? – W3Max 2012-03-02 15:57:46

1

简单的方法是[ImportMany]并让chosse拥有最高的元数据。 < - 这就是我们在我们的项目中所做的。

有关可以执行的操作的更多信息 - 您会发现here

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

PS:代码是手写的,所以LINQ是不对的 - 也许

编辑:

,而不是处理你们班的服务直接也可以导入和工厂至极有一些方法像:

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

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

恕我直言,这实在是太多了仪式。我不希望MEF决定我做事的方式。我希望它尽可能隐身。此外,这是一个框架,我不能控制人们如何需要依赖关系。我需要支持基本的构造函数注入。我知道[ImportMany],但这个问题恰恰是关于构造函数注入的。 – W3Max 2012-03-02 14:18:49

+0

工厂解决方案的好处是,你有一个容器,你可以从中得到你想要的东西。 – blindmeis 2012-03-06 06:19:57

+0

但你是对的,而不是IService,你必须导入IServiceFac – blindmeis 2012-03-06 10:32:55