OpCodes.Constrained 字段
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
约束执行虚拟方法调用的类型。
public: static initonly System::Reflection::Emit::OpCode Constrained;
public static readonly System.Reflection.Emit.OpCode Constrained;
staticval mutable Constrained : System.Reflection.Emit.OpCode
Public Shared ReadOnly Constrained As OpCode
字段值
注解
下表列出了指令的十六进制和Microsoft中间语言(MSIL)程序集格式,以及简短的参考摘要:
格式 | 程序集格式 | 描述 |
---|---|---|
FE 16 <T > |
约束。 thisType |
对约束为类型 T 的类型调用虚拟方法。 |
只有 callvirt
指令才允许 constrained
前缀。
此时 MSIL 堆栈的状态必须如下所示:
托管指针
ptr
推送到堆栈上。ptr
的类型必须是指向thisType
的托管指针(&
)。 请注意,这与不受支持的callvirt
指令的情况不同,该指令需要引用thisType
。通过
argN
arg1
的方法参数被推送到堆栈上,就像使用不受支持的callvirt
指令一样。
constrained
前缀旨在使 callvirt
指令以统一的方式进行,而与 thisType
是值类型还是引用类型无关。
当 callvirt
method
指令以 constrained
thisType
为前缀时,将按如下所示执行该指令:
如果
thisType
是引用类型(而不是值类型),则会取消引用ptr
并将其作为指向method
callvirt
的“this”指针传递。如果
thisType
是一种值类型,并且thisType
实现method
,则ptr
作为“this”指针传递给call
method
指令,以便通过thisType
实现method
。如果
thisType
是值类型,并且thisType
不实现method
则ptr
取消引用、装箱并作为指向callvirt
method
指令的“this”指针传递。
仅当在 Object、ValueType或 Enum 上定义 method
,而不是由 thisType
重写时,才会发生此最后一种情况。 在这种情况下,装箱会导致创建原始对象的副本。 但是,由于没有 Object、ValueType和 Enum 修改对象状态的方法,因此无法检测到此事实。
constrained
前缀支持创建泛型代码的 IL 生成器。 通常,callvirt
指令对值类型无效。 相反,IL 编译器在编译时有效地执行上面概述的“this”转换,具体取决于 ptr
的类型和要调用的方法。 但是,当 ptr
是编译时未知的泛型类型时,无法在编译时进行此转换。
constrained
操作码允许 IL 编译器以统一的方式调用虚拟函数,而与 ptr
是值类型还是引用类型无关。 尽管它适用于 thisType
是泛型类型变量的情况,但 constrained
前缀也适用于非泛型类型,并可以减少以语言生成虚拟调用的复杂性,这些语言隐藏值类型和引用类型之间的区别。
使用 constrained
前缀也避免了值类型的潜在版本控制问题。 如果未使用 constrained
前缀,则必须发出不同的 IL,具体取决于值类型是否替代 System.Object 的方法。 例如,如果值类型 V
重写 Object.ToString() 方法,则会发出 call
V.ToString()
指令;如果没有,则会发出 box
指令和 callvirt
Object.ToString()
指令。 如果以后删除了替代,则在前一种情况下可能会出现版本控制问题,在后一种情况下,如果添加了替代,则会出现版本控制问题。
constrained
前缀还可用于对值类型调用接口方法,因为实现接口方法的值类型方法可以使用 MethodImpl
进行更改。 如果未使用 constrained
前缀,编译器将强制选择在编译时要绑定到的值类型的哪一种方法。 使用 constrained
前缀,MSIL 可以绑定到在运行时而不是编译时实现接口方法的方法。
以下 Emit 方法重载可以使用 constrained
操作码: