实战MEF(5):导出元数据
如何理解元数
我们可以把元数据理解为随类型一起导出的附加信息。有时候我们会考虑,把元数据随类型一并导出,增加一些说明,使得我们在导入的时候,可以多一些筛选条件。
默认的类型导出带有元数据吗
上面的内容我说得比较简洁,也许您不是很理解,不要紧,在编程里面,很多东西我们都是写了代码后才理解的。所以,我的理论功底比较差,最不擅长的就是长篇大论,还是从代码中看吧。
我们首先要弄清楚一下问题:在我没有手动去添加元数据的默认导出类型,是否带有元数据。为了使代码更简单,这里我直接把一个类导出,而不编写公共接口了。

这里我们直接编写一个类,然后直接导入这个类型即可:

示例代码定在当前程序集中,可以在AssemblyCatalog范围查找。

AssemblyCatalog的Parts属性在智能提示中没有出现(从ComposablePartCatalog类继承下来,可能是因为虚方法没有被重写,所以没有在智能提示中显示出来),不过的确有这个属性,通过枚举Parts访问每个导出的组件类,而在ExportDefinitions属性中的每个ExportDefinition对象都有一个Metadata属性,它就是每个导出的元数据,为字典类型(IDictionary<string, object>),key是字符串类型,value是任意对象(Object)。
运行应用程序后,我们会看到如下图所示的内容:

这个例子表明,在默认情况下,导出是带有元数据的,从上面的运行结果可以猜到默认的元数据是用于说明导出组件的类型的。
如何导出元数据?
要导出元数据,除了对目标类型应用ExportAttribute特性外,还要用ExportMetadataAttribute特性来定义元数,在定义时遵循字典结构,即构造函数的两个参数分别代表key和value。如下面代码:

这两个元数据标记本组件的版本为200,作者是小王。我们知道元数据是IDictionary<string, object>字典结构,这就好办,我们在导入的时候使用Lazy<T, TMetadata>,以前我们用过Lazy<T>,现在因为带了元数据,所以就用Lazy<T, TMetadata>,然后让TMetadata的类型为IDictionary<string, object>就可以了。示例代码如下:

AssemblyCatalog cat = new AssemblyCatalog(typeof(Program).Assembly);
// 组装
CompositionContainer container = new CompositionContainer(cat);
Program p = new Program();
try
{
container.ComposeParts(p);
// 显示元数据
if (p.f_task.Metadata.ContainsKey("Ver"))
{
Console.WriteLine("版本号:{0}。", p.f_task.Metadata["Ver"].ToString());
}
if (p.f_task.Metadata.ContainsKey("Author"))
{
Console.WriteLine("作者:{0}。", p.f_task.Metadata["Author"].ToString());
}
Console.Write("\n\n");
// 测试调用
p.f_task.Value.OutPut();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
container.Dispose();
}
好了,运行一下,如图所示,我们已经把元数据也导入了。

还有另一种较为复杂的元数据导出导入方式,那就是自己实现的强类型元数据。我们来动手做做。
- 定义一个表示元数据的公共接口,名为ICustMetadata。
[MetadataViewImplementation(typeof(MyCustMetaData))]
public interface ICustMetadata
{
int Ver { get; } //版本
string Author { get; } //作者
}
在定义接口时,并加上MetadataViewImplementation特性,且指明哪些类将实现该接口。
2、上面我们指定了实现ICustMetadata的类为MyCustMetaData,所以接下来我们要定义这个类。
public class MyCustMetaData:ICustMetadata
{
IDictionary<string, object> m_dic;
// 构造函数
public MyCustMetaData(IDictionary<string, object> _pDic)
{
this.m_dic = _pDic;
}
public int Ver
{
get
{
if (m_dic.ContainsKey("Ver"))
{
return Convert.ToInt32(m_dic["Ver"]);
}
return -1;
}
}
public string Author
{
get
{
if (m_dic.ContainsKey("Author"))
{
return m_dic["Author"].ToString();
}
return string.Empty;
}
}
}
注意:定义元数据视图类时,必须包含带有一个IDictionary<string, object>类型参数的构造函数,否则将无法使用。我们通过前面的内容知道元数据其实是以字典形式存在的,故传给元数据视图类的构造函数的就是元数据的原始视图,只是我们用一个类来重封装了一下而已。
4、把调用的代码修改如下:
class Program
{
[Import]
public Lazy<TestTask, ICustMetadata> f_task;
static void Main(string[] args)
{
AssemblyCatalog cat = new AssemblyCatalog(typeof(Program).Assembly);
// 组装
CompositionContainer container = new CompositionContainer(cat);
Program p = new Program();
try
{
container.ComposeParts(p);
// 显示元数据
Console.WriteLine("元数据视图类型:{0}。", p.f_task.Metadata.GetType().Name);
// 显示元数据
Console.WriteLine("------- 元数据如下 --------");
Console.WriteLine("版本:{0}", p.f_task.Metadata.Ver);
Console.WriteLine("作者:{0}", p.f_task.Metadata.Author);
Console.Write("\n\n");
// 测试调用
p.f_task.Value.OutPut();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
container.Dispose();
}
Console.Read();
}
}
最后就得到如下图所示的结果:

元数据的实际类型正好是我们上面定义的MyCustMetaData类。
今天就到此为止吧,88各位。
实战MEF(5):导出元数据的更多相关文章
- C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)
上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...
- MEF只导出类的成员
MEF只导出类的成员 通过前面两篇文章的介绍,相信各位会明白MEF中有不少实用价值.上一文中我们也讨论了导入与导出,对于导出导入,今天我们再深入一点点,嗯,只是深入一点点而已,不会很难的,请大家务必放 ...
- [MEF]第03篇 MEF延迟加载导出部件及元数据
一.演示概述此演示介绍了MEF的延迟加载及元数据相关的内容.在实际的设计开发中,存在着某些对象是不需要在系统运行或者附属对象初始化的时候进行实例化的,只需要在使用到它的时候才会进行实例化,这种方式就可 ...
- 实战MEF(3):只导出类的成员
通过前面两篇文章的介绍,相信各位会明白MEF中有不少实用价值.上一文中我们也讨论了导入与导出,对于导出导入,今天我们再深入一点点,嗯,只是深入一点点而已,不会很难的,请大家务必放心,如果大家觉得看文章 ...
- 实战MEF(2):导出&导入
上一文中,我们大致明白了,利用MEF框架实现自动扫描并组装扩展组件的思路.本文我们继续前进,从最初的定义公共接口开始,一步步学会如何使用MEF. 在上一文中我们知道,对于每一个实现了公共规范的扩展组件 ...
- 实战MEF(4):搜索范围
在前面的文章中,几乎每个示例我们都会接触到扩展类的搜索位置,我们也不妨想一下,既然是自动扩展,它肯定会有一个或者多人可供查找的位置,不然MEF框架怎么知道哪里有扩展组件呢? 就像我们用导航系统去查找某 ...
- 实战MEF(1):一种不错的扩展方式
在过去,我们完成一套应用程序后,如果后面对其功能进行了扩展或修整,往往需要重新编译代码生成新的应用程序,然后再覆盖原来的程序.这样的扩展方式对于较小的或者不经常扩展和更新的应用程序来说是可以接受的,而 ...
- 【转】MEF程序设计指南四:使用MEF声明导出(Exports)与导入(Imports)
在MEF中,使用[System.ComponentModel.Composition.ExportAttribute]支持多种级别的导出部件配置,包括类.字段.属性以及方法级别的导出部件,通过查看Ex ...
- 实战MEF(1)一种不错的扩展方式
在过去,我们完成一套应用程序后,如果后面对其功能进行了扩展或修整,往往需要重新编译代码生成新的应用程序,然后再覆盖原来的程序.这样的扩展方式对于较小的或者不经常扩展和更新的应用程序来说是可以接受的,而 ...
随机推荐
- git: 常用功能等
1. an very useful simple git guide link: http://rogerdudler.github.io/git-guide/index.zh.html
- .NET CLI 命令
您可以立即使用的部分通用 .NET CLI 命令 命令 说明 dotnet new 使用 C# 语言初始化用于类库或控制台应用程序的有效项目. dotnet restore 还原在指定项目的 proj ...
- bzoj3673可持久化线段树实现可持久化数组实现可持久化并查集(好长)
线段树只用叶子节点感觉莫名浪费,,, 感觉真好写(刚从未来程序逃回来的人) #include <cstdio> #define mid ((l+r)>>1) ,ca,x,y; ...
- VirtualPathProvider的使用
解决的问题,加载数据库中的UI public class Global : System.Web.HttpApplication { protected void Application_Start( ...
- 经典排序算法 – 插入排序Insertion sort
经典排序算法 – 插入排序Insertion sort 插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. 插入排序方法分直接插入排序和折半插入排序两种, ...
- seajs学习一天后的总结归纳
公司项目最近需要将js文件迁移到seajs来进行模块化管理,由于我以前主要接触模块化开发是接触的AMD规范的requireJS,没有接触过CMD规范,而且在实际项目中还没有用过类似技术.于是,我非常兴 ...
- java的poi技术写Excel的Sheet
在这之前写过关于java读,写Excel的blog如下: Excel转Html java的poi技术读,写Excel[2003-2007,2010] java的poi技术读取Excel[2003-20 ...
- jquery easyui 动态绑定数据列
function doSearch2() { var strsql = $('#sssql').val(); $.ajax({ url: "../HttpHandler/DownloadHa ...
- Ejabberd导入到eclipse
ejabberd 在eclipse(erlide)中的配置.调试.运行 最近在折腾ejabberd,将ejabberd项目配置到eclipse中进行编译.调试等,现在将过程记下来,希望能帮助到需要 ...
- nmap
扫描端口 nmap -v -sS -open -iL iplist.txt -no-stylesheet -oX output.xml -p- -P0 -v 详细信息-sS 隐蔽扫描(半开syn).– ...