是否可以参数化MEF导入?

时间:2010-04-14 22:02:57

标签: .net mef composition

我对MEF比较新,所以我不完全了解这些功能。我正在努力实现与Unity的InjectionMember类似的东西。

假设我有一个导入MEF部件的类。为简单起见,我们将以下类作为导出部分的示例。

[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Logger {

    public string Category {
        get;
        set;
    }

    public void Write(string text) {
    }

}

public class MyViewModel {

    [Import]
    public Logger Log {
        get;
        set;
    }

}

现在我想弄清楚的是,是否可以在导入时为Category属性指定值。类似的东西:

public class MyViewModel {

    [MyImportAttribute(Category="MyCategory")]
    public Logger Log {
        get;
        set;
    }

}

public class MyOtherViewModel {

    [MyImportAttribute(Category="MyOtherCategory")]
    public Logger Log {
        get;
        set;
    }

}

目前,我正在做的是实现IPartImportsSatisfiedNotification并在代码中设置Category。但显然我宁愿将所有东西整齐地放在一个地方。

2 个答案:

答案 0 :(得分:6)

MEF programming guide中,请阅读Exports and Metadata部分。它显示了如何在导出的部件上添加元数据,方法是使用ExportMetadata属性或定义自己的自定义导出属性。

然后,您可以像这样定义ILoggerMetadata界面:

public interface ILoggerMetadata
{
    string Catagory { get; }
}

并执行ImportMany的{​​{1}}并在代码中选择您想要的那个:

IEnumerable<Lazy<ILogger,ILoggerMetadata>>

我同意将元数据约束直接放在import属性中更好,但目前在MEF开箱即用是不可能的。 (有可能扩展MEF来做到这一点。)

另一种方法是从private ILogger fooLogger; [ImportMany] public IEnumerable<Lazy<ILogger,ILoggerMetadata>> Loggers { set { this.fooLogger = value.First(x => x.Metadata.Catagory == "foo").Value; } } 派生IFooLogger接口,并在导入和导出中使用它。这很简单,与将约​​束放在导入中的效果基本相同。但是,如果您有多个元数据属性和/或许多可能的值,则此方法不起作用。

编辑:我巧妙地误解了你的问题;我认为这是关于约束导入,而不是使用一些额外的参数配置导入的对象。

我认为Kathleen Dollard的this recent post也存在同样的问题。此外,在this post about component relationships中,Nicholas Blumhardt将这种“参数化”关系建模为注入ILogger(或Func<X,Y>)。

您可以通过直接在方法上放置Func<ILogger,string>属性来在MEF中执行相同的操作。或者,如果您需要一个不那么模糊的合同,您可以定义一个[Export(typeof(Func<ILogger,string>))]接口并导入/导出:

ILoggerFactory

最后,你仍然需要在代码中调用工厂。

答案 1 :(得分:3)

在进一步深入研究MEF之后,似乎没有办法以声明的方式做到这一点。虽然您可以派生自己的导出属性,但似乎没有任何机制可以以任何有意义的方式派生导入属性。

但是,不是实现IPartImportsSatisfiedNotification,我可以做的(现在看来很明显)是在setter中设置类别。我必须放弃自动财产,但这就是生命。

public class MyViewModel {

    private Logger log;

    [Import]
    public Logger Log {
        get { return log; }
        set {
            log = value;
            log.Category = "MyCategory";
        }
    }

}