OpCodes.Readonly 字段
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
指定后面的数组地址操作在运行时不执行类型检查,并且返回可变性受限的托管指针。
public: static initonly System::Reflection::Emit::OpCode Readonly;
public static readonly System.Reflection.Emit.OpCode Readonly;
staticval mutable Readonly : System.Reflection.Emit.OpCode
Public Shared ReadOnly Readonly As OpCode
字段值
注解
下表列出了指令的十六进制和 Microsoft 中间语言 (MSIL) 程序集格式,以及简短的参考摘要:
格式 | 程序集格式 | 说明 |
---|---|---|
FE 1E | readonly。 | 指定后续数组地址操作在运行时不执行类型检查,并且返回具有受限可变性的托管指针。 |
此前缀只能紧跟在 ldelema
指令前面,并调用数组上的特殊 Address
方法。 它对后续操作的影响是双重的:
在运行时,不执行任何类型检查操作。 请注意,在引用类型数组上使用 时, 和
stelem
指令通常有一个隐式类型检查ldelema
。 值类永远不会有运行时类型检查,在这种情况下readonly
是无操作。验证程序将地址操作的结果视为具有受限可变性的托管指针。
据说指针具有受限的可变性,因为定义类型控制是否可以更改值。 对于不公开任何公共字段或更新值的方法的值类,指针是只读的, (因此前缀的名称) 。 具体而言,表示基元类型的类 (例如 System.Int32) 不公开变量,因此是只读的。
以这种方式受限制的托管指针只能通过以下方式使用:
作为
object
、、ldflda
、stfld
call
或constrained callvirt
指令的参数ldfld
。作为
pointer
指令或其中一个指令的参数ldobj
ldind
。source
作为指令的参数cpobj
。
不允许所有其他操作,包括 stobj
、 initobj
或 mkrefany
操作或任何 stind
指令。
前缀的目的是readonly
避免在从泛型代码中的数组中提取元素时检查类型。 例如,表达式 arr[i].m()
(其中数组 arr
的元素类型是一种泛型类型,该类型被限制为具有具有方法 m
的接口)可能会编译为以下 MSIL。
ldloc arr
ldloc i
readonly.
ldelema !0 // Loads the pointer to the object.
… // Load the arguments to the call.
constrained. !0
callvirt m
readonly
如果没有前缀,指令ldelema
将执行类型检查 !0 为引用类型的情况。 此类型不仅检查效率低下,而且在语义上不正确。 检查ldelema
的类型是完全匹配,太强。 如果数组包含类型为 !0 的子类,则上述代码将使类型检查失败。
提取数组元素的地址而不是元素本身,以便有一个句柄,该句柄 arr[i]
适用于值类型和引用类型,因此可以传递给 constrained callvirt
指令。
通常,如果数组包含引用类型的元素,则跳过运行时检查是不安全的。 为了确保安全,必须确保不通过此指针对数组进行任何修改。 验证程序规则确保这一点。 受限的托管指针可以作为实例方法调用的对象传递,因此严格地说,对于值类型,它不是只读的,但值类型不存在类型安全问题。
以下 Emit 方法重载可以使用 readonly
opcode: