第24章 元数据和特性
掌握元数据相关知识,对于更加深入地了解.NET大有裨益。正因为这个原因,我们特意安排了本章的内容,让读者在语法学习之余,逐渐积累对.NET体系结构的了解,从另一个角度来审视我们学过的知识。我个人比较喜欢从多个视角来观察同一个知识点,往往可以发现一些新的东西,这是我自己的学习方法,也建议大家尝试一下。
通过对本章的学习,我们将看到这些元数据究竟包含了哪些信息,这些元数据的作用是怎样的?是否可以自行扩展这些元数据信息?又该怎么做?我们还将学习特性,特性和元数据的关系是怎样的?希望大家能带着这些问题进行阅读,这样在阅读的过程中才更有针对性。
本章将首先介绍元数据的知识,之后再介绍特性,其中介绍了BCL中提供的一些预定义特性,以及如何创建自定义的特性。相信读完本章,读者都可以找到前面这些问题的答案。
24.1 元数据
所谓元数据(Metadata)就是描述数据的数据(Data about data)。我们在学习第22章程序集的时候,曾经提到过程序集清单中包括类型元数据。本节将进一步展开学习元数据这一概念。这些元数据包含了对模块或程序集中定义和引用的每个类型以及成员的说明,也包括引用的所有程序集在内。俗话说百闻不如一见,我们可以使用CFF Explorer工具[1]来查看示例程序(ProgrammingCSharp4.exe)中的元数据,如图24-1所示。
图 24-1 使用CFF Explorer查看程序集中的元数据
可见,元数据主要包含以下信息:
❑Module表。模块相关信息,这里的模块是可执行文件ProgrammingCSharp4.exe,如图24-2所示。
图 24-2 模块相关信息
❑TypeRef表。程序集中引用到的所有类型,例如System.Object、System.AsyncCallback等,如图24-3所示。
图 24-3 程序集引用到的类型
❑TypeDef表。类型定义列表,例如我们在讲表达式的时候定义的MethodSample类,它位于的名称空间,它继承自什么类型,它的字段列表是哪些(指向Field表的某些字段元素),它的方法有哪些(指向Method表的某些方法元素)。该表中不仅仅只有类的定义,还包含接口定义,如图24-4所示。
图 24-4 类型定义列表
❑FieldDef表。字段定义列表,包含了类型中定义的字段,包括编译器自动生成的字段,如图24-5所示。
图 24-5 字段定义列表
❑MethodDef表。方法定义列表,包含了类型中定义的方法,包括构造函数以及编译器自动生成的方法。其中每个方法包含了对参数表的引用,如图24-6所示。
图 24-6 方法定义表
❑Param表。参数定义列表,包含了方法定义中的各个参数,如图24-7所示。
图 24-7 参数定义表
❑MemberDef表。成员引用列表,描述引用成员的情况,引用成员可以是方法、字段或者属性。
❑Constant表。常数定义列表,描述参数、字段和属性的常数值。每个参数都有个"Parent"成员用于引用使用该常数的成员,如图24-8所示。
图 24-8 常数定义表
❑CustomAttribute表。自定义特性列表。
❑FieldMarshal表。描述了与非托管代码交互时,参数和字段的传递方式。
❑Event表。事件定义列表。
❑Property表。属性列表。
❑Assembly表。程序集定义。
❑AssemblyRef表。引用的程序集。
❑ManifestResource表。描述所使用的资源信息。
❑GenericParam表。所使用的所有泛型类型定义中或泛型方法使用的泛型参数。
其他还有一些元数据所包含的信息,这里不做介绍了。元数据是程序集的组成部分之一,可以使用ILDasm工具查看元数据在程序集中所占的比例,以及上述各种元数据表的元素数,如代码清单24-1所示。
代码清单24-1 程序集ProgrammingCSharp4.exe的一些统计信息
File size:26624
PE header size:512(496 used)(1.92%)
PE additional info:1619(6.08%)
Num.of PE sections:3
CLR header size:72(0.27%)
CLR meta-data size:17612(66.15%)
CLR additional info:2353(8.84%)
CLR method headers:489(1.84%)
Managed code:2998(11.26%)
Data:2048(7.69%)
Unaccounted:-1079(-4.05%)
Num.of PE sections:3
.text-24064
.rsrc-1536
.reloc-512
CLR meta-data size:17612
Module-1(10 bytes)
TypeDef-90(1260 bytes)31 interfaces,1 explicit layout
TypeRef-106(636 bytes)
MethodDef-142(1988 bytes)18 abstract,0 native,100 bodies
FieldDef-51(306 bytes)0 constant
MemberRef-105(630 bytes)
ParamDef-89(534 bytes)
Constant-14(84 bytes)
CustomAttribute-163(978 bytes)
NativeType-31(124 bytes)
ClassLayout-1(8 bytes)
StandAloneSig-17(34 bytes)
InterfaceImpl-14(56 bytes)
PropertyMap-8(32 bytes)
Property-16(96 bytes)
MethodSemantic-25(150 bytes)
TypeSpec-6(12 bytes)
Assembly-1(22 bytes)
AssemblyRef-4(80 bytes)
ManifestResource-1(12 bytes)
NestedClass-6(24 bytes)
EventMap-1(4 bytes)
Event-1(6 bytes)
FieldRVA-1(6 bytes)
GenericParam-4(32 bytes)
GenericParamConstraint-1(4 bytes)
Strings-5114 bytes
Blobs-3940 bytes
UserStrings-1172 bytes
Guids-16 bytes
Uncategorized-242 bytes
CLR additional info:2353
Resources-2353
CLR method headers:489
Num.of method bodies-100
Num.of fat headers-29
Num.of tiny headers-71
Num.of fat sections-0
Num.of small sections-4
Managed code:2998
Ave method size-29
24.1.1 从IntelliSense谈起
前文中不止一次提到过VisualStudio2010的IntelliSense功能,如图24-9所示,它在很大程度上方便了程序编写,提高了编码效率。
图 24-9 Visual Studio 2010的IntelliSense功能
事实上,IntelliSense功能就是在设计阶段读取程序集的元数据,来实现代码提示功能的。如果需要的话,当然也可以读取这些元数据信息。.NET Framework提供了几个重要的类,可以帮助我们访问程序集的相关信息。图24-10是这些类之间的关系图,从图中可以看到,Type、Assembly、Module、MemberInfo、MethodBase是抽象类。
图 24-10 .NET Framework提供的和元数据有关的类关系图
这些类的介绍如表24-1所示。
这些类的用法我们将在稍后进行介绍。
[1]CFF Explorer是一款支持.NET的PE文件编辑器。