实战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();

}

好了,运行一下,如图所示,我们已经把元数据也导入了。

还有另一种较为复杂的元数据导出导入方式,那就是自己实现的强类型元数据。我们来动手做做。

  1. 定义一个表示元数据的公共接口,名为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类。

时间: 2024-10-20 04:39:53

实战MEF(5):导出元数据的相关文章

[MEF]第03篇 MEF延迟加载导出部件及元数据

一.演示概述 此演示介绍了MEF的延迟加载及元数据相关的内容. 在实际的设计开发中,存在着某些对象是不需要在系统运行或者附属对象初始化的时候进行实例化的, 只需要在使用到它的时候才会进行实例化,这种方式就可以理解为对象的迟延初始化,或者叫迟延加载. 对于提升系统的性能大有裨益呀! 另外,还可以为导出的部件添加元数据,以便在代码中提供更加灵活的扩展办法,或获取更多的相关信息.甚至,还可以自定义元数据的接口,无论是定义还是使用都非常的方便. 相关下载(屏幕录像):http://yunpan.cn/c

实战MEF(2):导出&amp;导入

上一文中,我们大致明白了,利用MEF框架实现自动扫描并组装扩展组件的思路.本文我们继续前进,从最初的定义公共接口开始,一步步学会如何使用MEF. 在上一文中我们知道,对于每一个实现了公共规范的扩展组件,都需要进行导出,随后我们的主应用程序文件中会自动进行组装.这便产生了一个疑问:为什么需要导出? 如果大家还记得,以前我们用VC++写.dll文件时,都会把需要提供给别人调用的函数标记为导出函数,这样别人才能调用我们编写的函数.就好比我们的家,我们一般会有客厅,既然叫客厅,当然是展现给客人看的.有客

实战MEF(3):只导出类的成员

过前面两篇文章的介绍,相信各位会明白MEF中有不少实用价值.上一文中我们也讨论了导入与导出,对于导出导入,今天我们再深入一点点,嗯,只是深入一点点而已,不会很难的,请大家务必放心,如果大家觉得看文章枯燥,不妨一边喝牛奶一边阅读. 上一文中我们都是把整个类型(整个类)进行导出,不过有时候,我们可能会考虑只导出类的某些成员,比如某个属性或某个字段等. 我们还是少说理论,免得大家喝不下牛奶,还是直接上菜吧.为了便于测试,以下示例把组件都写在当前程序集中,也就是在同一个项目,然后用AssemblyCat

实战MEF(1)

在过去,我们完成一套应用程序后,如果后面对其功能进行了扩展或修整,往往需要重新编译代码生成新的应用程序,然后再覆盖原来的程序.这样的扩展方式对于较小的或者不经常扩展和更新的应用程序来说是可以接受的,而对于像ERP系统那样复杂而且常常需要扩展的应用程序,这种扩展方法就不够方便,因为每次都要修改源代码或重新引用组件. 尤其是组件(许多dll),如果每编写一个新组件又要在主项目中引用一次,显然主项目就不得不经常重新生成.要是能有一种机制,可以在主项目应用程序不作任何修改就可以自动识别并扩展组件,就会很

实战MEF(4):搜索范围

在前面的文章中,几乎每个示例我们都会接触到扩展类的搜索位置,我们也不妨想一下,既然是自动扩展,它肯定会有一个或者多人可供查找的位置,不然MEF框架怎么知道哪里有扩展组件呢? 就像我们用导航系统去查找某个地方的所有旅店一样,正因为在该地的旅店已在数据库中注册了相关信息,我们的导航系统才能查找到它,如果某家旅店没有向导航数据库提供任何数据,那很显然导航系统是无法识别到它的详细地址的. MEF对扩展组件的查找范围通常有三个: AssemblyCatalog:从某个程序集中查找. Application

C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 下面我们来主要讲解一下MEF中的导入和导出,还是上一篇的代码(这篇中,我还会贴出完整的代码),修改Program的代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Compo

【转】MEF程序设计指南四:使用MEF声明导出(Exports)与导入(Imports)

在MEF中,使用[System.ComponentModel.Composition.ExportAttribute]支持多种级别的导出部件配置,包括类.字段.属性以及方法级别的导出部件,通过查看ExportAttribute的源代码就知道ExportAttribute被定义为Attribute,并为其设置了使用范围. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA18

es实战之数据导出成csv文件

从es将数据导出分两步: 查询大量数据 将数据生成文件并下载 本篇主要是将第二步,第一步在<es实战之查询大量数据>中已讲述. csv vs excel excel2003不能超过65536, excel2007及以上版本支持1048576条数据.excel支持的数据量有限,并且生生成文件的速度比较慢. csv具有支持写入量大,文件较小的优点. 故选择csv作为导出文件类型. 导出文件的几种方式: 将数据从es中查询出来,在这个大前提下,对比导出文件的速度. 由前端处理 直接将数据返回给前端,

基于SSM的POI导入导出Excel实战第二篇-导出EXCEL

业务需求:这里我以产品信息为例,用于POI导入导出Excel实战的操作对象 需求分析:我们要导出的数据格式比较简单,其实就是待导出的表(视图)的数据,如下图所示: 实现思路:A.会发现待导出的数据列表是一个矩阵式的格式,即二维的形式 B.其中的头部id name unit price stock 等字段field是固定不变的,将会充当excel的头部 C.以数据行的角度观察数据列表,会发现每一行每一列的值都是B所指的那些字段一一对应的取值value D.由此可以得出这些数据组织是由每一行数据组成