ECMA-335 (CLI) 标准 读书笔记——总结CLI类型系统(下)
接上篇:ECMA-335 (CLI) 标准 读书笔记——总结CLI类型系统(上)
第二部 15.5.4 数据类型转换
当数据类型转换需要指定平台时,这个标准指定了一个最小的数据类型集,这些类型应该被所有符合CLI的实现所支持。另外的数据类型能通过指定平台的方式来被支持,用定制的属性和(或)定制的修饰语来指定任何要求在特定实现上的特定的操作。
下列的数据类型应该通过所有符合CLI的实现被转换;本地数据类型要实现:
- 所有的整型数据类型 (int8, int16, unsigned int8, bool, char等),包括native整型类型。
- 枚举,作为基本数据类型。
- 所有的浮点数据类型(float32和 float64),如果它们被CLI托管代码的实现支持。
- 类型string
- 上面所有类型的非托管指针
另外,当托管代码转成非托管代码的时候,下列的数据类型应当被支持,但并不需要反向支持(也就是说,当调用非托管方法时看做返回类型,或者当从非托管方法到托管方法的调用时看做参数):
- 上面任何基于零的一维数组
- 委托(非托管代码调用委托的机制是平台指定的;它不应该假定委托转换后将产生一个可直接在非托管代码中使用的函数指针)
最后,类型System.Runtime.InteropServices.GCHandle能被用于转换一个对象到非托管代码。该非托管代码接收了一个平台指定的数据类型,该数据类型能被当做一个特定对象的“不透明处理”。参见第四部分。
第二部 23.1.16 用于签名中的元素类型
下面的表列出了ELEMENT_TYPE常量的值。它们被广泛地用于元数据签名块,参见第23.2章:
Name |
Value |
Remarks |
ELEMENT_TYPE_END |
0x00 |
Marks end of a list |
ELEMENT_TYPE_VOID |
0x01 |
|
ELEMENT_TYPE_BOOLEAN |
0x02 |
|
ELEMENT_TYPE_CHAR |
0x03 |
|
ELEMENT_TYPE_I1 |
0x04 |
|
ELEMENT_TYPE_U1 |
0x05 |
|
ELEMENT_TYPE_I2 |
0x06 |
|
ELEMENT_TYPE_U2 |
0x07 |
|
ELEMENT_TYPE_I4 |
0x08 |
|
ELEMENT_TYPE_U4 |
0x09 |
|
ELEMENT_TYPE_I8 |
0x0a |
|
ELEMENT_TYPE_U8 |
0x0b |
|
ELEMENT_TYPE_R4 |
0x0c |
|
ELEMENT_TYPE_R8 |
0x0d |
|
ELEMENT_TYPE_STRING |
0x0e |
|
ELEMENT_TYPE_PTR |
0x0f |
Followed by type |
ELEMENT_TYPE_BYREF |
0x10 |
Followed by type |
ELEMENT_TYPE_VALUETYPE |
0x11 |
Followed by TypeDef or TypeRef token |
ELEMENT_TYPE_CLASS |
0x12 |
Followed by TypeDef or TypeRef token |
ELEMENT_TYPE_VAR |
0x13 |
Generic parameter in a generic type definition, represented as number |
ELEMENT_TYPE_ARRAY |
0x14 |
type rank boundsCount bound1 … loCount lo1 … |
ELEMENT_TYPE_GENERICINST |
0x15 |
Generic type instantiation. Followed by type typearg- count type-1 ... type-n |
ELEMENT TYPE TYPEDBYREF |
0x16 |
|
ELEMENT_TYPE_I |
0x18 |
System.IntPtr |
ELEMENT_TYPE_U |
0x19 |
System.UIntPtr |
ELEMENT_TYPE_FNPTR |
0x1b |
Followed by full method signature |
ELEMENT_TYPE_OBJECT |
0x1c |
System.Object |
ELEMENT_TYPE_SZARRAY |
0x1d |
Single-dim array with 0 lower bound |
ELEMENT_TYPE_MVAR |
0x1e |
Generic parameter in a generic method definition, represented as number |
ELEMENT_TYPE_CMOD_REQD |
0x1f |
Required modifier followed by a TypeDef or TypeRef token |
ELEMENT_TYPE_CMOD_OPT |
0x20 |
Optional modifier followed by a TypeDef or TypeRef token |
ELEMENT_TYPE_INTERNAL |
0x21 |
Implemented within the CLI |
ELEMENT_TYPE_MODIFIER |
0x40 |
Or’d with following element types |
ELEMENT_TYPE_SENTINEL |
0x41 |
Sentinel for vararg method signature |
ELEMENT_TYPE_PINNED |
0x45 |
Denotes a local variable that points at a pinned object |
|
0x50 |
Indicates an argument of type System.Type. |
|
0x51 |
Used in custom attributes to specify a boxed object (§23.3). |
|
0x52 |
Reserved |
|
0x53 |
Used in custom attributes to indicate a FIELD (§22.10, 23.3). |
|
0x54 |
Used in custom attributes to indicate a PROPERTY (§22.10, 23.3). |
|
0x55 |
Used in custom attributes to specify an enum (§23.3). |
第二部23.2.12 类型
类型在签名中如下编码(I1是ELEMENT_TYPE_I1的缩写词,U1是ELEMENT_TYPE_U1的缩写词等,参见23.1.16章):
Type ::=
BOOLEAN | CHAR | I1 | U1 | I2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U
| ARRAY Type ArrayShape (general array, see §23.2.13)
| CLASS TypeDefOrRefEncoded
| FNPTR MethodDefSig
| FNPTR MethodRefSig
| GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *
| MVAR number
| OBJECT
| PTR CustomMod* Type
| PTR CustomMod* VOID
| STRING
| SZARRAY CustomMod* Type (single dimensional, zero-based array i.e., vector)
| VALUETYPE TypeDefOrRefEncoded
| VAR number
非终结符GenArgCount 是一个int32值 (压缩的) ,在该签名中指定了泛型参数的数量。
第二部 23.2.16 短形式的签名
签名的通用规范在如何编码某些项的时候保留了一些灵活性。例如,以下面的形式编码String似乎是有效的:
long-form: (ELEMENT_TYPE_CLASS, 到System.String的类型引用 )
short-form: ELEMENT_TYPE_STRING
只有短形式是有效的。下面的表列出了哪些短形式应该被用来替换长形式。(通常,为了紧凑,ELEMENT_TYPE_前缀被省略了,所以VALUETYPE代表了ELEMENT_TYPE_VALUETYPE的短形式。)
Long Form |
Short Form | |
Prefix |
TypeRef to: |
|
CLASS |
System.String |
STRING |
CLASS |
System.Object |
OBJECT |
VALUETYPE |
System.Void |
VOID |
VALUETYPE |
System.Boolean |
BOOLEAN |
VALUETYPE |
System.Char |
CHAR |
VALUETYPE |
System.Byte |
U1 |
VALUETYPE |
System.Sbyte |
I1 |
VALUETYPE |
System.Int16 |
I2 |
VALUETYPE |
System.UInt16 |
U2 |
VALUETYPE |
System.Int32 |
I4 |
VALUETYPE |
System.UInt32 |
U4 |
VALUETYPE |
System.Int64 |
I8 |
VALUETYPE |
System.UInt64 |
U8 |
VALUETYPE |
System.IntPtr |
I |
VALUETYPE |
System.UIntPtr |
U |
VALUETYPE |
System.TypedReference |
TYPEDBYREF |
第二部 23.4 Marshalling descriptors
Marshalling Descriptor类似于一个签名——它是一个二进制数据块。描述了当调用或者被非托管代码经过平台调用的时候,一个字段或参数(通常,方法的返回值作为第0个参数)应该如何被转换。
注意一个符合CLI的实现仅仅需要支持更早期特定类型的转换,见15.5.4章。
Marshalling Descriptor使用名字为NATIVE_TYPE_xxx的常量。它们的名字和值如下表:
Name |
Value |
NATIVE_TYPE_BOOLEAN |
0x02 |
NATIVE_TYPE_I1 |
0x03 |
NATIVE_TYPE_U1 |
0x04 |
NATIVE_TYPE_I2 |
0x05 |
NATIVE_TYPE_U2 |
0x06 |
NATIVE_TYPE_I4 |
0x07 |
NATIVE_TYPE_U4 |
0x0b |
NATIVE_TYPE_I8 |
0x09 |
NATIVE_TYPE_U8 |
0x0a |
NATIVE_TYPE_R4 |
0x0b |
NATIVE_TYPE_R8 |
0x0c |
NATIVE_TYPE_LPSTR |
0x14 |
NATIVE_TYPE_LPWSTR |
0x15 |
NATIVE_TYPE_INT |
0x1f |
NATIVE_TYPE_UINT |
0x20 |
NATIVE_TYPE_FUNC |
0x26 |
NATIVE_TYPE_ARRAY |
0x2a |
这个块有下列格式:
MarshalSpec ::=
NativeIntrinsic
| ARRAY ArrayElemType
| ARRAY ArrayElemType ParamNum
| ARRAY ArrayElemType ParamNum NumElem
NativeIntrinsic ::=
BOOLEAN | I1 | U1 | I2 | U2 | I4 | U4 | I8 | U8 | R4 | R8
| LPSTR | LPSTR | INT | UINT | FUNC
第三部分 1.1 数据类型
当CTS定义了一个富类型系统,CLS指定了一个能被用于语言互操作的子集时,CLI本身处理一套简单得多的类型集。这些类型包括用户自定义的值类型和内建类型的子集。该子集,统称为“基本CLI类型”,包含了下面的类型:
- 完整的数字类型子集(int32, int64, native int和F)。
- 对象引用(O),被引用的对象类型间无区别。
- 指针类型(native unsigned int 和 &),被指向的类型无区别。
注意对象引用和指针类型能被赋予值null。这在CLI中被定义为零(所有位全为零的位组合格式)。
【注:至于关于VES在求值栈上的操作,就只有一个浮点类型,VES不关心其大小。VES仅在存储这些值到或者读取这些值从堆,静态,本地变量或者方法参数时,才弄清楚这些数字值的大小。】
总结一下:
第二部 7.1章列出了高级语言层面所有CLI支持的内建类型;
第二部 7.4章列出了高级语言层面所有CLI支持的本地类型;
第二部 23.1.16列出了metadata中能以二进制形式记录的内建类型;
第二部 23.4列出了metadata中能以二进制形式记录的本地类型;