Windows 元数据 (WinMD) 文件

Windows 运行时 (WinRT) .winmd API 在计算机可读元数据文件中进行了介绍,扩展名为 (也称为 Windows 元数据) 。 工具和语言投影使用这些元数据文件来启用语言投影。

一般说明

Windows包括系统提供的所有 WinRT API 的元数据。 Windows API 有助于语言投影在运行时解析需要此元数据的命名空间和类型。 Windows SDK 在单个文件中提供系统元数据的副本,供编译时需要此元数据的语言投影使用。

第三方可以开发自己的 WinRT API,这些 API 可以像系统提供的 API 一样参与语言投影。 第三方 WinRT API 必须提供元数据,就像系统 API 一样。 Windows命名空间和类型解析的 API 处理第三方元数据,就像它们处理系统元数据一样。

WinMD 文件的所有公共类型都必须是 WinRT 类型,并且必须携带 tdWindowsRuntime 标志 (类型标志的详细信息才能遵循) 。 WinMD 文件可能包含非 WinRT 类型的元数据。 WinMD 文件的任何非 WinRT 类型不得为公共类型。 非 WinRT 类型的语义是实现定义的,超出了本文档的范围。

WinRT 类型上 (方法、属性和事件) 接口成员必须是 WinRT 接口成员。 WinRT 类型可能包括非 WinRT 接口成员的元数据。 任何非 WinRT 接口成员可能不是公共的。 非 WinRT 接口成员的语义是实现定义的,超出了本文档的范围。

WinMD 文件

WinMD 文件格式

WinMD 文件使用与 CLR 程序集 (公共语言运行时) ,如 ECMA-335 规范所定义。 但是,虽然物理文件格式相同,但 WinMD 文件和 CLR 程序集的有效数据组合规则有所不同。 本文档列出了 WinMD 文件和 CLR 程序集之间的增量。

系统提供的 WinMD 文件是纯元数据。 第三方 WinMD 文件可能包含代码。 具体而言,托管 WinMD 文件包括 Microsoft 中间语言 (MSIL) 代码,就像传统 CLR 程序集一样。

每个 WinMD 文件都包含零个或多个 WinRT 类型的定义。 从技术上说,空 WinMD 文件有效。

WinMD 中列出的 PEKind 或计算机体系结构没有特定的 WinRT 限制。

WinMD 版本字符串必须包含"Windows 运行时 1.2"。

WinMD 文件名

没有 (WinMD) 的名称必须与 WinMD 文件中程序集表的名称列不区分大小写匹配。 例如,"Foo.Bar.winmd"文件必须在程序集表 Foo.Bar 名称列中具有"Foo.Bar"。 由于文件系统不区分大小写,因此文件名的大小写可能与程序集表名列值不同。

给定 WinMD 文件的所有 WinRT 类型都必须在与 WinMD 文件名和程序集表名列值匹配的命名空间下。 由于文件系统不区分大小写,因此文件名的大小写可能与给定 WinMD 文件中所有 WinRT 类型的命名空间不同。 给定 WinMD 中所有 WinRT 类型的命名空间必须与程序集表名列值完全匹配 (,即区分大小写) 。 例如,程序集表名称列中具有"Foo.Bar"的文件的所有类型都必须在"Foo.Bar"命名空间中。 这些类型可以是此命名空间的直接子 (例如 Foo.Bar.MyType) ,也可以在此命名空间的子命名空间中 (例如 Foo.Bar.Baz.MyType) 。 文件的名称必须是"Foo.Bar.winmd",但大小写可能有所不同,即"foo.bar.winmd"和"FOO"。酒吧。还可以将 WINMD"作为此元数据文件的文件名。

WinMD 组合

系统中所有类型的元数据分布在多个 .winmd 文件中。 AppX 包可以包含零个或多个描述应用程序包中包含的第三方 WinRT 组件的 .winmd 文件。

在系统提供的所有 .winmd 文件中,或包含在给定应用中,每个 WinRT 类型的元数据都必须存储在 WinMD 文件中,其最长名称与类型的命名空间匹配。 作为给定命名空间的直接子项的所有类型必须位于同一文件中。 例如,如果 AppX 包包含 Foo.winmd 和 Foo.Bar.winmd 文件,则 Foo.Bar.Baz.MyType 类型必须位于 Foo.Bar.winmd 文件中,因为该文件是包中类型命名空间匹配文件名最长的文件。

TypeDef 重定向

系统提供的元数据文件永远不会直接引用 TypeDef。 即使引用在同一元数据文件中定义的类型,系统元数据文件也始终引用 TypeRef,而该 TypeRef 又引用 TypeDef。 这样做是为了支持将 IVectorT< (IListT><>的 CLR 类型重定向,例如) 。

第三方元数据文件可以直接使用 TypeDef,也可以像系统元数据文件一样通过 TypeRef 重定向所有类型引用。

类型系统编码

本文档中 mscorlib 程序集中的系统命名空间的所有类型都由 WinRT 用作标记。 这些类型用于指示有关类型的信息,永远不应解析。 这包括 (,但不限于) System.Object、System.Guid、System.ValueType、System.Enum、System.MulticastDelegate 和 System.Attribute。 请注意,选择这些名称是为了与 CLR 兼容。 CLR 定义这些类型属于其类型系统,与 WinRT 无关。

请注意,此处所述的许多构造都使用 C# 语法。 这仅仅是因为使用 C# 语法表示某些公共语言基础结构 (CLI) 元数据构造。 实际构造是纯 CLI 元数据构造。

命名空间

WinRT 在单个以期间分隔的字符串中对类型的命名空间和本地名称进行编码。 例如,此代码片段中定义的类型为"Windows。Foundation.ISimpleInterface"。

namespace Windows {
    namespace Foundation {
        interface ISimpleInterface {
            HRESULT Method1(int paramOne);
        };
    };
};

对于空间优化,CLI 元数据中的 TypeDef 表为类型名称和命名空间名称提供了单独的列。 但是,在 API 级别,TypeDef 属性只公开类型名称。

基本类型

除 Guid 之外的所有 WinRT 基本类型都有显式常量值,用于 CLI 元数据 blob 和其他类型引用。 CLI 规范的分区 2 第 23.1.16 节中介绍了这些常量值。

WinRT 类型 CLI 元素类型名称 CLI 元素类型值
Int16 ELEMENT_TYPE_I2 0x06
Int32 ELEMENT_TYPE_I4 0x08
Int64 ELEMENT_TYPE_I8 0x0a
UInt8 ELEMENT_TYPE_U1 0x05
UInt16 ELEMENT_TYPE_U2 0x07
UInt32 ELEMENT_TYPE_U4 0x09
UInt64 ELEMENT_TYPE_U8 0x0b
Single ELEMENT_TYPE_R4 0x0c
Double ELEMENT_TYPE_R8 0x0d
Char16 ELEMENT_TYPE_CHAR 0x03
Boolean ELEMENT_TYPE_BOOL 0x02
字符串 ELEMENT_TYPE_STRING 0x0e

由于它没有显式 ELEMENT_TYPE_ * 常量值,因此 Guid 在元数据中表示为从 mscorlib 程序集的 Guid.empty 到 Guid.empty 类型。

枚举

枚举表示为 TypeDef 表中的一行 (ECMA 22.37) ,列设置如下。

  • 随意. 设置为公共 |密封 |tdWindowsRuntime (0x4101) 。
  • 名称: 包含类型名称的字符串堆中的索引。
  • 命名空间。 包含类型的命名空间的字符串堆中的索引。
  • 延续. 设置为在 mscorlib 程序集中引用 system.exception 类的 TypeRef。
  • FieldList. 字段表中的索引,用于标记此类型拥有的连续运行字段的第一个。
  • MethodList. 必须为空。

枚举具有一个实例字段,该字段指定枚举的基础整数类型以及零个或多个静态字段;枚举类型定义的每个枚举值对应一个。

枚举的基础整数类型作为字段表中的第一行出现 (ECMA 22.15) 与该类型相关联, (也就是说,在) 上面指定的 FieldList 列中引用的另一个行。 枚举类型的字段表中的列如下所示。

  • 标志:专用 |SpecialName |0x601) 的 (。
  • Name:包含名称 "value__" 的字符串堆中的索引。
  • 签名:包含 FieldSig blob 的 blob 堆中的索引 (ECMA 23.2.4) ,其中类型设置为 ELEMENT_TYPE_I4 或 ELEMENT_TYPE_U4,因为 WinRT 枚举值必须是有符号或无符号32位整数。

枚举值定义为枚举中的每个值提供字段定义。

  • 标志:公共 |static |文本 |hasdefault (0x8056) 。
  • Name:包含枚举值的名称的字符串堆中的索引。
  • 签名:包含 FieldSig blob 的 blob 堆中的索引 (ECMA 23.3.4) ,类型设置为枚举类型的 TypeDef。

对于每个枚举值定义,常量表中都有相应的行 (ECMA 22.9) 存储枚举值的整数值。

  • 键入 。 一个字节用于表示枚举的基础类型,ELEMENT_TYPE_I4 或 ELEMENT_TYPE_U4,后跟一个以 ECMA 规范为单位的字节填充零。
  • Parent:在字段表中保留关联的枚举值记录的索引。
  • 值:包含枚举值的整数值的 blob 表的索引。

此外,必须将 FlagsAttribute 添加到具有基础 UInt32 类型的任何枚举的枚举 TypeDef 行。 不能将 FlagsAttribute 添加到具有基础 Int32 类型的枚举的枚举 TypeDef 行。

对于所有系统提供的枚举,必须将 VersionAttribute 添加到枚举 TypeDef 行。 或者,可以将 VersionAttribute 添加到任何静态字段行。 如果存在,则任何枚举字段行上的 VersionAttribute 中的版本值都必须大于或等于枚举 TypeDef 行上 VersionAttribute 的值。

结构

结构作为 TypeDef 表中的一行实现 (ECMA 22.37) ,并按如下所示设置列。

  • 标志–公共 |密封 |顺序 |tdWindowsRuntime (0x4109) 。
  • Name –包含类型名称的字符串堆中的索引。
  • 命名空间–包含类型命名空间的字符串堆中的索引。
  • "扩展" –设置为在 mscorlib 程序集中引用 System.object 类的 TypeRef。
  • FieldList-字段表中的索引,用于标记此类型拥有的连续运行字段的第一个。
  • MethodList –必须为空。

结构具有一个或多个字段表项。

  • Flags: public。
  • Name:包含字段名称的字符串堆中的索引。
  • 签名:包含 FieldSig blob 的 blob 堆中的索引 (ECMA 23.2.4) ,其类型设置为字段类型的元数据标记。
    • 结构字段必须是基本类型、枚举或其他结构。

对于所有系统提供的结构,必须将 VersionAttribute 添加到结构 TypeDef 行。

委托

委托作为 TypeDef 表中的一行实现 (ECMA 22.37) ,并按如下所示设置列。

  • Flags:设置为 Public |密封 |tdWindowsRuntime (0x4101) 。
  • Name –包含类型名称的字符串堆中的索引。
  • 命名空间–包含类型命名空间的字符串堆中的索引。
  • 扩展:设置为在 mscorlib 程序集中引用 System.multicastdelegate 类的 TypeRef。
  • FieldList:必须为空。
  • MethodList: MethodDef 表的索引 (ECMA 22.26) ,并标记此类型拥有的方法的连续运行中的第一个。

委托的 TypeDef 行必须具有 GuidAttribute。

委托正好有两个 MethodDef 表项。 第一种定义构造函数。 此构造函数是一个兼容性标记,这就是为什么它使用非 WinRT 构造(如 native int)和既 in 不是也 out 不是的参数的原因。 WinRT 委托没有此类构造函数方法。

  • RVA: 0 (这是抽象构造) 。
  • ImplFlags: runtime (0x03) 。
  • 标志:专用 |hidebysig |specialname |0x1881) 的 (。
  • 名称:字符串表中包含名称 ".ctor" 的索引。
  • 签名:包含 MethodDefSig blob 的 blob 堆中的索引 (ECMA 23.2.1) 用于具有对象的方法,并在参数中为 native int,没有返回值。
  • ParamList:参数表的索引 (ECMA 22.33) ,其中包含与此方法关联的参数行运行中的第一个。 Param 表中的每一行都包含以下信息。
    • 对象参数
      • 序列1
      • Name "object"
      • Flags: none (0x00)
    • Native Int 参数
      • 序列2
      • Name "method"
      • Flags: none (0x00)

第二个 MethodDef 项定义调用方法。

  • RVA: 0 (这是抽象构造)
  • ImplFlags: runtime (0x03)
  • 标志:公共 |Virtual |HideBySig |specialname (0x08C6)
  • 名称:字符串表中包含名称 "Invoke" 的索引
  • 签名:包含委托的参数类型和返回类型的 MethodDefSig blob) (的 blob 堆中的索引。 如果委托已参数化,则 MethodDefSig blob 应通过 GENERICINST 编码类型引用每个委托类型参数 (如 ECMA II. 23.2.12) 。 要遵循的参数化委托的详细信息。
  • ParamList:参数表的索引 (ECMA 22.33) ,其中包含与此方法关联的参数行运行中的第一个。 Param 表中的每一行都将包含以下信息。
    • 标志–输入或输出,适用于参数
    • 序列–参数的序列顺序。 为方法的返回值保留零
    • Name – 索引到包含参数名称的字符串堆 中。对于系统提供的所有委托,必须将 VersionAttribute 添加到委托的 TypeDef 行。

参数化委托

参数化委托具有以下附加要求。

  • 参数化委托的名称后面追加了一个反号和一个数字,表示参数化委托具有的类型参数数。 例如,Windows。Foundation.EventHandlerT<> 类型存储在元数据中,其名称Windows。Foundation.EventHandler'1.
  • 参数化委托在 GENERICParam 表中有一行 (ECMA II.22.20) ,列设置如下。
    • Number:泛型参数的索引,从左到右编号,从零开始。
    • 标志:无。
    • 所有者:索引到包含 接口的行的 TypeDef 表中。
    • 名称:索引到包含泛型参数名称的字符串堆中。

ECMA II.23.2.14 (TypeSpec 表) 定义参数化委托的实例。 然后,可以在方法签名中使用这些 TypeSpecs,类似于 TypeRefs。

接口

接口在 ECMA II.22.37 (TypeDef 表中作为行实现,) 列设置如下。

  • 标记:
    • 接口|公共|abstract |tdWindowsRuntime (0x40A1) ,或
    • 接口|NotPublic|abstract |tdWindowsRuntime (0x40A0)
  • 名称:包含接口名称的字符串表中的索引。
  • 命名空间 - 字符串堆中的索引,该字符串堆包含类型的命名空间。
  • 扩展:null。
  • FieldList:必须为空。
  • MethodList:MethodDef 表中的索引,标记此类型拥有的方法的第一个连续运行。 当前部分各小节中详细介绍了 MethodDef 表的内容。

接口的 TypeDef 行必须具有 GuidAttribute 和 VersionAttribute。

任何具有专用可见性的 WinRT 接口都必须具有单个 ExclusiveToAttribute。 任何具有公共可见性的 WinRT 接口不得具有 ExclusiveToAttribute。 如果存在,ExclusiveToAttribute 必须引用运行时类。

接口所需的接口由 INTERFACEImpl 表中的行表示 (ECMA II.22.23) 列设置如下。

  • 类:包含 接口的行的 TypeDef 表中的索引。
  • 接口:TypeDef、TypeRef 或 TypeSpec 表中指定所需接口的索引。 请注意,在系统提供的元数据文件中,即使在同一元数据文件中定义了所需的接口,这也永远不会是 TypeDef。 有关更多详细信息,请参阅 TypeDef 重定向部分。

参数化接口

参数化接口具有以下附加要求。

参数化接口的名称后面追加了一个反号和一个数字,表示参数化委托具有的类型参数数。 例如,Windows。Foundation.Collections.IVectorT<> 类型存储在元数据中,其名称Windows。Foundation.Collections.IVector'1.

参数化接口在 GenericParam 表中有一行 (ECMA II.22.20) ,列设置如下。

  • Number:泛型参数的索引,从左到右编号,从零开始。
  • 标志:无。
  • 所有者:索引到包含 接口的行的 TypeDef 表中。
  • 名称:索引到包含泛型参数名称的字符串堆中。

ECMA II.23.2.14 (TypeSpec 表) 用于定义参数化接口的实例。 然后,可以在方法签名和接口实现中使用这些 TypeSpecs,类似于 TypeRefs。

接口成员

数组参数

为任何接口成员类型编码 Array 参数时,在 MethodDefSig blob 以及 params 表中都省略紧接在数组参数前的数组长度参数。

数组参数的方向直接在元数据中编码。 数组长度参数的方向可以推断如下。

  • 如果数组参数是 in 参数,则数组长度参数也必须是 in 参数。
  • 如果数组参数是 out 参数,并且未携带 BYREF 标记,则数组长度为 in 参数。
  • 如果数组参数是 out 参数,并且携带 BYREF 标记,则数组长度为 out 参数。

方法

为了更好地为方法的预期投影和 CLR 兼容性建模,所需的 HRESULT 返回值不会在元数据中编码。 相反,要用作返回值的 out 参数在 methodDefSig 中编码为返回值。 对于未声明要用作返回值的 out 参数的方法,methodDefSig 必须将返回类型声明为 void (根据 ECMA II.23.2.11) 。

接口上的每个方法都将表示为 MethodDef 表中的行。 每个 methoddef 行都将包含以下信息。

  • RVA:0x00
  • ImplFlags:0x00
  • 标志:公共|虚拟|HideBySig |抽象|NewSlot |实例 (0x5c6)
  • 名称:包含方法名称的字符串表中的索引
  • 签名:包含 MethodDefSig blob (ECMA II.23.2.1) 包含方法的参数类型和返回类型的 blob 堆的索引。 如果接口已参数化,则 MethodDefSig blob 应按 ECMA II.23.2.12) 通过 GENERICINST 编码类型 (引用接口的每个类型参数。 有关要遵循的参数化接口的详细信息。
  • ParamList:参数表 (ECMA II.22.33) 包含与此方法关联的 Param 行运行中的第一个索引。

方法的每个参数 (加上返回值(如果指定) 则参数表 (ECMA II.22.33) 。

  • Flags – 无,根据参数的合适方式输入或退出。
    • 返回值始终为 none
    • 其他参数始终为"输入"或"out"
  • 序列 – 参数的序列顺序。
    • 为方法的返回值保留零
  • Name – 索引到包含参数名称的字符串堆中。

每个方法可以选择具有一个 OverloadAttribute,该重载将唯一的方法名称 (接口的作用域内) 。 每个方法可以选择有一个 DefaultOverloadAttribute,用于指示应在弱动态类型化语言中以弱类型语言 (在参数) 中预测的相同 arity (的重载方法。

属性

接口上的每个属性定义为属性 (ECMA II.22.34) 、PropertyMap (ECMA II.22.35) 、MethodSemantics (ECMA II.22.28) 和 MethodDef (ECMA II.22.26) 表中的行。

每个具有一个或多个属性的接口将在 PropertyMap 表中表示为包含以下信息的单个行。

  • 父级:TypeDef 表中包含包含属性的接口的索引。
  • PropertyList:Property 表的索引,其中包含与此类型关联的行运行中的第一个索引。

每个属性将在包含以下信息的 Property 表中表示为单个行

  • 标志:无。
  • 名称:包含属性名称的字符串堆中的索引。
  • 类型:索引到包含 PropertySig blob 的 blob 堆 (ECMA II.23.2.5) 包含属性的类型信息。

每个属性将在 MethodDef 表中表示为一行或两行。 只读属性表示为具有"get_"前缀的单个方法,而读/写属性表示为两种方法,一个方法具有"get_",另一个方法具有"put_"前缀。 get 方法的签名不采用任何参数,并返回属性类型的值。 set 方法的签名采用属性类型的单个参数,不返回任何内容。

属性的 MethodDef 行包含以下内容。

  • RVA:0
  • ImplFlags:无
  • 标志:公共|virtual |HideBySig |newSlot |abstract |specialname (0xDC6)
  • 名称:包含"get_PropertyName>"<或"put_PropertyName>"<的字符串表中的索引
  • 签名:Blob 堆中的索引,其中包含 MethodDefSig blob (ECMA II.23.2.1) ,其中包含上述方法的参数类型和返回类型。
  • ParamList:参数表 (ECMA II.22.33) 包含与此方法关联的 Param 行运行中的第一个索引。 Param 表中的值与上述方法下指定的值相同。

属性的每个 MethodDef 行在 MethodSemantics 表中都有一个关联的行,其中包含以下信息。

  • 语义:根据情况使用 Getter 或 Setter。
  • 方法:索引到包含 getter 或 setter 方法的 MethodDef 表中。
  • 关联:索引到包含 属性的 Property 表中。

事件

接口上的每个事件都定义为 22.13) 、EventMap (ECMA 22.12) 中 (的行、MethodSemantics (ECMA II. 22.28) 和 MethodDef (表。

包含一个或多个事件的每个接口都将在 EventMap 表中表示为单个行,其中包含以下信息。

  • Parent:包含属性的接口的 TypeDef 表中的索引。
  • EventList:事件表中的索引,其中包含与此类型关联的行中的第一个。

每个事件都将表示为包含以下信息的事件表中的单个行。

  • EventFlags: None。
  • 名称:包含属性名称的字符串堆中的索引。
  • 类型类型:一个 TypeDefOrRef,用于索引到包含事件委托类型的相应表中。

每个事件都将在 MethodDef 表中表示为两行,一个包含用于添加事件侦听器的 "add_" 前缀,另一个包含用于删除事件侦听器的 "remove_" 前缀。 Add 方法采用委托实例,并返回 Windows。表示事件注册的 EventRegistrationToken。 Remove 方法使用 add 方法返回的 EventRegistrationToken 取消注册事件。

事件的 MethodDef 行包含以下各项。

  • RVA:0
  • ImplFlags: None
  • 标志:公共 |最终 |virtual |hidebysig |newslot |specialname (0x09e6)
  • 名称:字符串表中的索引,其中包含相应的 "add_ < propertyname > " 或 "remove_ < propertyname > "。
  • 签名:包含 MethodDefSig blob (ECMA 23.2.1) 的 blob 堆中的索引,其中包含方法的参数和返回类型,如下所述。
    • Add_ 方法采用委托类型的单个参数,并返回一个 Windows。EventRegistrationToken。
    • Remove_ 方法采用单个 Windows。EventRegistrationToken 参数,并且不返回任何内容。
  • ParamList:参数表的索引 (ECMA 22.33) ,其中包含与方法关联的参数行运行中的第一个。 参数表中的值是在上述方法中指定的。

事件的两个 MethodDef 行在 MethodSemantics 表中都有一个关联的行,其中包含以下信息。

  • 语义:加载项或 RemoveOn。
  • 方法:对包含添加或删除侦听器方法的 MethodDef 表的索引。
  • 关联:在包含事件的事件表中建立索引。

运行时类

运行时类作为 TypeDef 表中的一行实现 (ECMA 22.37) ,并按如下所示设置列。

  • Flags:所有运行时类必须携带公共、自动布局、类和 tdWindowsRuntime 标志。
    • 仅限静态的类携带抽象标志。 所有其他类不会携带抽象标志。
    • 不能组合的类携带密封标志。 可组合类不携带密封标志。
  • 名称:包含类名的字符串表中的索引。
  • 命名空间–包含类型命名空间的字符串堆中的索引。
  • 扩展:在 mscorlib 中引用可组合类或 System.object 的索引。
  • FieldList:必须为空。
  • MethodList: MethodDef 表的索引,用于标记此类型所拥有的方法的连续运行的第一个。 下面详细介绍了 MethodDef 表的内容。

对于所有系统提供的类,必须将 VersionAttribute 添加到类的 TypeDef 行。

实现的接口

由运行时类实现的接口由 InterfaceImpl 表中的行表示 (ECMA 22.23) ,并按如下所示设置列。

  • 类:包含类型的行的 TypeDef 表中的索引。
  • 接口:用于指定实现的接口的 TypeDef、TypeRef 或 TypeSpec 表中的索引。 请注意,在系统提供的元数据文件中,即使所需的接口是在同一个元数据文件中定义的,也不会使用 TypeDef。 有关更多详细信息,请参阅 "TypeDef 重定向" 部分。

运行时类必须仅指定其一个 InterfaceImpl 行的 DefaultAttribute。

运行时类可以对其任何 InterfaceImpl 行指定 OverridableAttribute 或 ProtectedAttribute。 它们不能在同一行中同时指定 OverridableAttribute 和 ProtectedAttribute。

可以选择将 VersionAttribute 添加到类的任何 interfaceImpl 行。 任何类的 interfaceImpl 行上的 VersionAttribute 中的版本值必须大于或等于类的 TypeDef 行上 VersionAttribute 中的值。

静态接口

运行时类有零个或多个 StaticAttribute 自定义特性。 指定多个 StaticAttribute 自定义特性是合法的,只要它们具有不同的指定参数即可。 所有 StaticAttribute 都将显示为 CustomAttribute 表中的一行,其中包含以下信息。

  • Parent: StaticAttribute 关联的运行时类。
  • 类型:对 StaticAttribute 的 .ctor 的引用。
  • 值:一个自定义属性 blob,其中包含 System.object 静态接口参数和 Uint32 版本参数。

激活

运行时类有零个或多个 ActivatableAttribute 自定义特性。 指定多个 ActivatableAttribute 自定义特性是合法的,只要它们具有不同的指定参数即可。 所有 ActivatableAttributes 都将显示为 CustomAttribute 表中的一行,其中包含以下信息。

  • Parent: ActivatableAttribute 关联的运行时类。
  • 类型:对 ActivatableAttribute 的其中一个 ctor 的引用。
    • 直接激活:仅采用 Uint32 版本参数的 .ctor。
    • 工厂激活:采用系统类型工厂接口参数和 Uint32 版本参数的 .ctor。
  • 值:包含 System.web interface 参数的自定义属性 blob (如果提供) 和 Uint32 版本参数。

组合

运行时类有零个或多个 ComposableAttribute 自定义特性。 指定多个 ComposableAttribute 自定义特性是合法的,只要它们具有不同的指定参数即可。 所有 ComposableAttribute 都将显示为 CustomAttribute 表中的一行,其中包含以下信息。

  • Parent: ComposableAttribute 关联的运行时类。
  • 类型:对 ComposableAttribute 的 .ctor 的引用。
  • 值:包含 System.object 组合工厂接口接口参数的自定义属性 blob、 (公共或受保护) 的枚举值以及 Uint32 版本参数。

类方法

对于与类关联的每个接口上的每个方法,运行时类在 MethodDef 表中都有一行。 这包括成员接口 (正常、受保护和可重写的) 、静态接口、激活工厂接口和可组合的工厂接口。 此外,支持直接激活的类还会在 MethodDef 表中包含一行来指示这一点。

成员界面成员

成员接口中的每个方法 (包括受保护的和可重写的接口) 由类的 MethodDef 表中的行表示。 类的 methodDef 表包含来自原始声明接口的 MethodDef 信息的精确副本,包括参数表行和自定义属性,但以下情况例外。

  • 运行时类可为成员接口上定义的方法指定替代名称。
  • 运行时类的方法不会获得抽象标志。
  • 运行时类的方法获取运行时 MethodImpl 标志。
  • 不能重写的接口中的方法还获取最终标志。 可重写接口中的方法不会获得最终标志。

成员接口中的类的 MethodDef 表中的每一行都连接回接口方法,该方法最初通过 MethodImpl 表中的条目来定义方法 (ECMA 22.27) ,其值如下所示。

  • Class – TypeDef 表中的一个索引,该索引引用携带方法的类 (注意,此索引不受 TypeDef 重定向) 的限制。
  • MethodBody – MethodDef 表中引用类方法的索引。
  • MethodDeclaration – MethodDef 或 MemberRef 表中引用最初声明的接口方法的索引。
静态接口成员

静态接口中的每个方法都用类的 MethodDef 表中的行表示。 类的 methodDef 表包含来自原始声明接口的 MethodDef 信息的精确副本,包括参数表行和自定义属性,但以下情况例外。

  • 静态成员不会获得 Virtual、Abstract、NewSlot 和 Instance 标志。
  • 静态成员确实会获得静态和类标志。
  • 运行时类上的静态方法获取运行时 MethodImpl 标志。
激活成员

支持直接的无参数激活的类具有类的 MethodDef 表中具有以下列值的构造函数行。

  • RVA:0x00
  • ImplFlags:运行时
  • 标志:公共 |HideBySig |SpecialName |RTSpecialName |实例
  • 名称:包含".ctor"的字符串表中的索引
  • 签名:包含 MethodDefSig blob 的 blob 堆的索引 (ECMA II.23.2.1) 不包含参数并返回 null
  • ParamList:必须为空

支持工厂激活的类在类的 MethodDef 表中具有构造函数行,用于每个实现的工厂接口中每个方法,并具有以下列值。

  • RVA:0x00
  • ImplFlags:运行时
  • 标志:公共|HideBySig |SpecialName |RTSpecialName |实例
  • 名称:包含".ctor"的字符串表中的索引。
  • 签名:Blob 堆中的索引,其中包含包含 MethodDefSig blob (ECMA II.23.2.1) ,其中包含输入参数并返回 null。
  • ParamList:指向 Params 表的指针,每个参数都有一行,完全从 params 表复制,用于最初声明工厂方法。
组合成员

支持组合工厂激活的类在类的 MethodDef 表中具有构造函数行,用于每个实现的工厂接口中每个方法,并具有以下列值。

  • RVA:0x00
  • ImplFlags:运行时
  • 标志:公共|HideBySig |SpecialName |RTSpecialName |实例
  • 名称:包含".ctor"的字符串表中的索引。
  • 签名:Blob 堆中的索引,其中包含包含 MethodDefSig blob (ECMA II.23.2.1) ,其中包含自定义输入参数并返回 null。 控制 IInspectable* [in] 参数和非委托 IInspectable** [out] 参数不会反映在方法签名中。
  • ParamList:指向 Params 表的指针,每个参数都有一行,控制 IInspectable* [in] 参数和非委托 IInspectable** [out] 参数除外,该参数完全从 params 表中复制,用于最初声明工厂方法。

自定义特性

自定义属性具有零个或多个构造函数方法,每个方法具有零个或多个参数,其中参数类型限制为基本类型、枚举和 System.Type。 自定义属性中的每个构造函数在 MethodDef 中显示为一行,并包含以下信息。

  • RVA (相对虚拟地址) :null
  • ImplFlags:无
  • 标志:公共|HideBySig |specalname |RTSpecialName (0x1886)
  • 名称:字符串表中包含名称".ctor"的索引。
  • 签名:包含 MethodDefSig blob (ECMA II.23.2.1) 包含方法的参数类型和返回类型的 blob 堆的索引。
  • ParamList:参数表 (ECMA II.22.33) 包含与此方法关联的 Param 行运行中的第一个索引。

元数据构造上的自定义属性作为行存储在 CustomAttribute 表 (ECMA II.22.10) 中,列设置如下。

  • 父级:自定义属性附加到的元数据表中的索引。
  • 类型:在 MethodDef 或 MemberRef 表中编制索引,该表包含对特性类型的构造函数的引用。
  • 值:索引到包含 ECMA II.23.2 (位置和命名属性参数的 blob 堆) 。 请注意,由于不允许 WinRT 自定义属性具有属性,因此自定义属性 blob 永远不会包含 PROPERTY 样式的命名参数。