元数据(Metadata)和自定义导出(Custom Export)
在MEF中,导出可提供自身的一些附加信息,我们称之为“元数据”。可通过元数据将导出的一些信息、属性传递给导入。上一篇介绍导入的时候提到了ImportMany,在ImportMany的时候有时候可能需要根据特定的条件过滤一些匹配的导出,这时我们可以利用导出的元数据作依据。此外,由于导入部件可以使用元数据来决定要使用哪些导出,或收集有关导出的信息而不必构造导出。 因此,导入必须为延迟导入才能使用元数据。
使用元数据需要定义一个称为“元数据视图”的接口,元数据视图中有且只能定义只读的属性,可以使用特性
[DefaultValue]给属性默认值,元数据视图中定义的所有属性在使用时都必须赋值,否则使用改元数据的导出将与任何导入匹配失败,当然我们也可以使用[DefaultValue]设置默认值,这样被[DefaultValue]修饰的属性便可以认为是可选属性了。例:
public interface ILogMetadata
{
[DefaultValue("FileLog")]
string LogType{ get; }
string Name{ get; }
}
使用元数据视图的导出
[Export(typeof(ILog))]
[ExportMetadata("Name", "FileLog")]
[ExportMetadata("LogType", "FileLog")]
public class FileLog: ILog
{
}
注意:特性ExportMetadata的参数第一个为属性名称,第二个是属性的值。组合容器在组合时部件时会自动匹配所有的元数据视图,如果有符合的元数据视图则该导出部件视为匹配成功。
匹配导入(匹配含有元数据修饰的导出,导入需要使用延时加载):
public class MyLog
{
[Import]
public Lazy<ILog, ILogMetadata> singleLog { get; set; }
[ImportMany]
public IEnumerable<Lazy<ILog, ILogMetadata>> logs;
}
自定义导出
在上面的示例中我们可能会想,当元数据视图的的必选属性有很多时,我们是不是得使用很多的[ExportMetadata]来修饰导出,另外元数据视图的写法也很容易出错,其实MEF中可以对Export 和 InheritedExport 进行扩展,用于将元数据封装到自定义特性中。
自定义特性可以指定ContractType、ContractName或任何其他元数据。 为了定义自定义特性,必须使用 MetadataAttribute 特性来修饰继承自 ExportAttribute(或 InheritedExportAttribute)的类。 例:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]//指定特性的作用域
public class FileLogExportAttribute : ExportAttribute
{
public FileLogExportAttribute(string logType)
: base(typeof(ILog))
{
LogType= logType;
Name = "FileLog";
}
public string LogType{ get; private set; }
public string Name{ get; private set; }
}
使用自定义导出修饰前面导出:
1 [FileLogExport("FileLog")) 2 public class FileLog: ILog 3 { 4 }
使用自定义导出的特性,ContractType是隐式定义的,