【问题标题】:Overriding MEF Composition覆盖 MEF 组合
【发布时间】:2012-03-02 02:21:08
【问题描述】:

如何覆盖 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],但这个问题正是关于构造函数注入。

【问题讨论】:

    标签: .net mef


    【解决方案1】:

    除了将优先级元数据放在零件上,您还可以将它们放在不同的目录中,然后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>();
    

    【讨论】:

    • 对不起,如果我很慢,但我不明白这对构造函数注入有何帮助。
    • 构造函数注入没有冲突,我们也用这个。
    • 我没有说有问题,我只是说我不明白它是如何工作的。再次抱歉,但我是 MEF 世界的新手。你能在上面的例子中解释一下吗?
    • 我看到了你对这个问题的回答:stackoverflow.com/questions/7750640/…你认为 InterceptingCatalog 对我的情况有帮助吗?
    • 谢谢!我今晚会试试这个,但它似乎可以完成这项工作。我想我只需要按优先级过滤服务,只保留优先级最高的服务作为 priorityCatalog 并将所有服务添加到 mainCatalog?
    【解决方案2】:

    最简单的方法是 [ImportMany] 并选择具有最高元数据的那个。

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

    【讨论】:

    • 恕我直言,这太过分了。我不希望 MEF 决定我做事的方式。我希望它尽可能不可见。此外,这是一个框架,我无法控制人们如何需要依赖项。我需要支持基本的构造函数注入。我知道 [ImportMany],但这个问题正是关于构造函数注入。
    • 工厂解决方案的好处是,你有一个容器,你可以从中得到你想要的。
    • 但你是对的,你必须导入 IServiceFac 而不是 IService
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 2019-07-30
    • 2011-07-12
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    相关资源
    最近更新 更多