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)程序集格式,以及简短的参考摘要:
| Format | 程序集格式 | 说明 |
|---|---|---|
| FE 1E | readonly。 | 指定后续数组地址操作在运行时不执行类型检查,并返回具有受限可变性的托管指针。 |
此前缀只能紧靠在 ldelema 指令前面,对数组上的特殊 Address 方法的调用。 它对后续操作的影响是两倍:
在运行时,不会执行类型检查操作。 请注意,在引用类型数组上使用时,通常存在隐式类型检查
ldelema和stelem说明。 永远不会对值类进行运行时类型检查,因此readonly在这种情况下,no-op。验证程序将地址操作的结果视为具有受限可变性的托管指针。
指针据说具有受限的可变性,因为定义类型控制值是否可以改变。 对于公开没有就地更新值的公共字段或方法的值类,指针是只读的(因此前缀的名称)。 具体而言,表示基元类型的类(例如 System.Int32)不公开 mutator,因此是只读的。
以这种方式限制的托管指针只能通过以下方式使用:
作为 、
objectldfldldflda、stfldcall或constrained callvirt指令的参数。pointerldobj作为指令的参数或指令之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 操作码: