OpCodes.Constrained 字段

定义

约束执行虚拟方法调用的类型。

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 堆栈的状态必须如下所示:

  1. 托管指针 ptr推送到堆栈上。 ptr 的类型必须是指向 thisType的托管指针(&)。 请注意,这与不受支持的 callvirt 指令的情况不同,该指令需要引用 thisType

  2. 通过 argNarg1 的方法参数被推送到堆栈上,就像使用不受支持的 callvirt 指令一样。

constrained 前缀旨在使 callvirt 指令以统一的方式进行,而与 thisType 是值类型还是引用类型无关。

callvirtmethod 指令以 constrainedthisType为前缀时,将按如下所示执行该指令:

  • 如果 thisType 是引用类型(而不是值类型),则会取消引用 ptr 并将其作为指向 methodcallvirt 的“this”指针传递。

  • 如果 thisType 是一种值类型,并且 thisType 实现 method,则 ptr 作为“this”指针传递给 callmethod 指令,以便通过 thisType实现 method

  • 如果 thisType 是值类型,并且 thisType 不实现 methodptr 取消引用、装箱并作为指向 callvirtmethod 指令的“this”指针传递。

仅当在 ObjectValueTypeEnum 上定义 method,而不是由 thisType重写时,才会发生此最后一种情况。 在这种情况下,装箱会导致创建原始对象的副本。 但是,由于没有 ObjectValueTypeEnum 修改对象状态的方法,因此无法检测到此事实。

constrained 前缀支持创建泛型代码的 IL 生成器。 通常,callvirt 指令对值类型无效。 相反,IL 编译器在编译时有效地执行上面概述的“this”转换,具体取决于 ptr 的类型和要调用的方法。 但是,当 ptr 是编译时未知的泛型类型时,无法在编译时进行此转换。

constrained 操作码允许 IL 编译器以统一的方式调用虚拟函数,而与 ptr 是值类型还是引用类型无关。 尽管它适用于 thisType 是泛型类型变量的情况,但 constrained 前缀也适用于非泛型类型,并可以减少以语言生成虚拟调用的复杂性,这些语言隐藏值类型和引用类型之间的区别。

使用 constrained 前缀也避免了值类型的潜在版本控制问题。 如果未使用 constrained 前缀,则必须发出不同的 IL,具体取决于值类型是否替代 System.Object 的方法。 例如,如果值类型 V 重写 Object.ToString() 方法,则会发出 callV.ToString() 指令;如果没有,则会发出 box 指令和 callvirtObject.ToString() 指令。 如果以后删除了替代,则在前一种情况下可能会出现版本控制问题,在后一种情况下,如果添加了替代,则会出现版本控制问题。

constrained 前缀还可用于对值类型调用接口方法,因为实现接口方法的值类型方法可以使用 MethodImpl进行更改。 如果未使用 constrained 前缀,编译器将强制选择在编译时要绑定到的值类型的哪一种方法。 使用 constrained 前缀,MSIL 可以绑定到在运行时而不是编译时实现接口方法的方法。

以下 Emit 方法重载可以使用 constrained 操作码:

适用于