实战MEF(5):导出元数据

摘要:
首先,我们需要明确我没有手动添加元数据的默认导出类型是否具有元数据。如何导出元数据?如以下代码所示:这两个元数据将此组件的版本标记为200,作者是小王。还有另一种更复杂的导出和导入元数据的方法,即您自己实现的强类型元数据。定义表示元数据的公共接口,名为ICustMetadata。

如何理解元数

我们可以把元数据理解为随类型一起导出的附加信息。有时候我们会考虑,把元数据随类型一并导出,增加一些说明,使得我们在导入的时候,可以多一些筛选条件。

默认的类型导出带有元数据吗

上面的内容我说得比较简洁,也许您不是很理解,不要紧,在编程里面,很多东西我们都是写了代码后才理解的。所以,我的理论功底比较差,最不擅长的就是长篇大论,还是从代码中看吧。

我们首先要弄清楚一下问题:在我没有手动去添加元数据的默认导出类型,是否带有元数据。为了使代码更简单,这里我直接把一个类导出,而不编写公共接口了。

实战MEF(5):导出元数据第1张

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

实战MEF(5):导出元数据第2张

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

实战MEF(5):导出元数据第3张

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

运行应用程序后,我们会看到如下图所示的内容:

实战MEF(5):导出元数据第4张

这个例子表明,在默认情况下,导出是带有元数据的,从上面的运行结果可以猜到默认的元数据是用于说明导出组件的类型的。

如何导出元数据

要导出元数据,除了对目标类型应用ExportAttribute特性外,还要用ExportMetadataAttribute特性来定义元数,在定义时遵循字典结构,即构造函数的两个参数分别代表key和value。如下面代码:

实战MEF(5):导出元数据第5张

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

实战MEF(5):导出元数据第6张

AssemblyCatalog cat = newAssemblyCatalog(typeof(Program).Assembly);

// 组装

CompositionContainer container = newCompositionContainer(cat);

Program p = newProgram();

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(" ");

// 测试调用

p.f_task.Value.OutPut();

}

catch(Exception ex)

{

Console.WriteLine(ex.Message);

}

finally

{

container.Dispose();

}

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

实战MEF(5):导出元数据第7张

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

  1. 定义一个表示元数据的公共接口,名为ICustMetadata。

[MetadataViewImplementation(typeof(MyCustMetaData))]

publicinterfaceICustMetadata

{

int Ver { get; } //版本

string Author { get; } //作者

}

在定义接口时,并加上MetadataViewImplementation特性,且指明哪些类将实现该接口。

2、上面我们指定了实现ICustMetadata的类为MyCustMetaData,所以接下来我们要定义这个类。

publicclassMyCustMetaData:ICustMetadata

{

IDictionary<string, object> m_dic;

// 构造函数

public MyCustMetaData(IDictionary<string, object> _pDic)

{

this.m_dic = _pDic;

}

publicint Ver

{

get

{

if (m_dic.ContainsKey("Ver"))

{

returnConvert.ToInt32(m_dic["Ver"]);

}

return -1;

}

}

publicstring Author

{

get

{

if (m_dic.ContainsKey("Author"))

{

return m_dic["Author"].ToString();

}

returnstring.Empty;

}

}

}

注意:定义元数据视图类时,必须包含带有一个IDictionary<string, object>类型参数的构造函数,否则将无法使用。我们通过前面的内容知道元数据其实是以字典形式存在的,故传给元数据视图类的构造函数的就是元数据的原始视图,只是我们用一个类来重封装了一下而已。

4、把调用的代码修改如下:

classProgram

{

[Import]

publicLazy<TestTask, ICustMetadata> f_task;

staticvoid Main(string[] args)

{

AssemblyCatalog cat = newAssemblyCatalog(typeof(Program).Assembly);

// 组装

CompositionContainer container = newCompositionContainer(cat);

Program p = newProgram();

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(" ");

// 测试调用

p.f_task.Value.OutPut();

}

catch(Exception ex)

{

Console.WriteLine(ex.Message);

}

finally

{

container.Dispose();

}

Console.Read();

}

}

最后就得到如下图所示的结果:

实战MEF(5):导出元数据第8张

元数据的实际类型正好是我们上面定义的MyCustMetaData类。

今天就到此为止吧,88各位。

免责声明:文章转载自《实战MEF(5):导出元数据》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇FiddlerEverywhere安装与使用如何利用pip自动生成和安装requirements.txt依赖下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java IO流字符流简介及基本使用

                Java IO流字符流简介及常用字符流的基本使用     字符流分为输入字符流(Writer)和输出字符流(Reader),这两种字符流及其子类字符流都有自己专门的功能。在编码中我们常用的输出字符流有FileWriter、PrintWriter等,而常用的输入字符流有StringReader、FileReader、Buffe...

把大文件切割成小文件

package com.jm.label.tools;/*** 把大文件切割成小文件*/import java.io.File;import java.io.FileInputStream; import java.io.FileNotFoundException;import java.io.FileOutputStream; import java.io...

Java安全之安全加密算法

Java安全之安全加密算法 0x00 前言 本篇文来谈谈关于常见的一些加密算法,其实在此之前,对算法的了解并不是太多。了解的层次只是基于加密算法的一些应用上。也来浅谈一下加密算法在安全领域中的作用。写本篇文也是基于算法的应用和实现,也是我的基本原则,能用就行。 0x01 算法体制 在加密算法里面大致分为四大类:对称加密算法、非对称加密算法、散列函数、组合加...

Android 项目中文件夹的说明与作用(转)

(转自:http://blog.csdn.net/goodshot/article/details/11529731)   Android 项目中文件夹的作用 1. src:存放所有的*.java源程序。 2. gen:为ADT插件自动生成的代码文件保存路径,里面的R.java将保存所有的资源ID。 3. assets:可以存放项目一些较大的资源文件,例...

Assembly中Load, LoadFrom, LoadFile以及AppDomain, Activator类中相应函数的区别

Assembly和AppDomain的一些关于动态加载程序集的函数有些令人头疼,但细细研究后还是可以将他们区分的。 这些函数大致可以分为四类: 第一类:加载到Load Context内 Load Context: Load Context是所有动态加载程序集首选应该被加载到的地方。 它只能加载在AppDomain信息中的ApplicationBase目录...

上传下载后台函数以及前端脚本(webuploader) 备份

1 import java.io.BufferedOutputStream; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.PrintWriter; 5 import java.io.UnsupportedEncodingExce...