覆盖MEF组合物

时间:2012-03-02 02:21:08

标签: .net 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)
    {

    }
}

由于IService有多个实现,因此通常不会满足ServiceWithDependencies。但我想修改MEF(覆盖/拦截某些东西),以便它使用优先级元数据并将具有最高优先级的实现注入ServiceWithDependencies构造函数。

修改1

我不希望MEF决定我做事的方式。我希望它尽可能地隐形。此外,这是一个框架,我无法控制人们将如何需要依赖。我需要支持基本的构造函数注入。我知道[ImportMany],但这个问题正是关于构造函数注入。

2 个答案:

答案 0 :(得分: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>();

答案 1 :(得分:1)

简单的方法是[ImportMany],然后选择具有最高元数据的那个。 &lt; - 那就是我们在项目中所做的事情。

有关您可以做什么的更多信息 - 您会找到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();
    }
}