OpCodes.Constrained 字段


约束要对其进行虚方法调用的类型。Constrains the type on which a virtual method call is made.

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)程序集格式以及简短的参考摘要:The following table lists the instruction's hexadecimal and Microsoft intermediate language (MSIL) assembly format, along with a brief reference summary:

格式Format 程序集格式Assembly Format 说明Description
FE 16 < T @ NO__T-1FE 16 < T > 有限.constrained. thisType 对被约束为类型 T 的类型调用虚拟方法。Call a virtual method on a type constrained to be type T.

仅在 @no__t 1 指令上允许 @no__t 0 前缀。The constrained prefix is permitted only on a callvirt instruction.

此时 MSIL 堆栈的状态必须如下所示:The state of the MSIL stack at this point must be as follows:

  1. 托管指针 ptr 将被推送到堆栈上。A managed pointer, ptr, is pushed onto the stack. @No__t 的类型必须是 thisType 的托管指针(&)。The type of ptr must be a managed pointer (&) to thisType. 请注意,这与没有前缀 callvirt 指令的情况不同,后者需要引用 thisTypeNote that this is different from the case of an unprefixed callvirt instruction, which expects a reference of thisType.

  2. 方法参数 arg1argN 将被推送到堆栈上,就像使用没有前缀 callvirt 指令一样。Method arguments arg1 through argN are pushed onto the stack, just as with an unprefixed callvirt instruction.

@No__t-0 前缀旨在允许以统一的方式进行 @no__t 的指令,而不管 thisType 是值类型还是引用类型。The constrained prefix is designed to allow callvirt instructions to be made in a uniform way independent of whether thisType is a value type or a reference type.

如果 @no__t 0 @no__t 的指令以 constrained @no__t 为前缀,则按如下方式执行指令:When a callvirt method instruction has been prefixed by constrained thisType, the instruction is executed as follows:

  • 如果 @no__t 为引用类型(而不是值类型),则将取消引用 ptr,并将其作为 "this" 指针传递到 @no__t 的 callvirtIf thisType is a reference type (as opposed to a value type) then ptr is dereferenced and passed as the 'this' pointer to the callvirt of method.

  • 如果 @no__t 为值类型,thisType 实现了 method,则将 ptr 作为 "this" 指针传递给 call method 指令,以 thisType 的实现实现 @no__t。If thisType is a value type and thisType implements method then ptr is passed unmodified as the 'this' pointer to a call method instruction, for the implementation of method by thisType.

  • 如果 @no__t 为值类型,并且 thisType 未实现 method,则将 ptr 取消引用并装箱,并将其作为 "this" 指针传递到 @no__t @no__t。If thisType is a value type and thisType does not implement method then ptr is dereferenced, boxed, and passed as the 'this' pointer to the callvirt method instruction.

这种情况仅在以下情况下才会发生:在 ObjectValueType 或 @no__t 3 上定义 @no__t,而不是 @no__t 进行重写。This last case can occur only when method was defined on Object, ValueType, or Enum and not overridden by thisType. 在这种情况下,装箱会导致生成原始对象的副本。In this case, the boxing causes a copy of the original object to be made. 但是,因为没有 @no__t 的方法 ValueTypeEnum 修改对象的状态,所以无法检测到这种情况。However, because none of the methods of Object, ValueType, and Enum modify the state of the object, this fact cannot be detected.

@No__t 的前缀支持创建泛型代码的 IL 生成器。The constrained prefix supports IL generators that create generic code. 通常,callvirt 指令对于值类型无效。Normally the callvirt instruction is not valid on value types. 相反,IL 编译器必须在编译时有效地执行上述 "this" 转换,具体取决于 @no__t 的类型和正在调用的方法。Instead it is required that IL compilers effectively perform the 'this' transformation outlined above at compile time, depending on the type of ptr and the method being called. 但是,当 ptr 是在编译时未知的泛型类型时,不能在编译时进行此转换。However, when ptr is a generic type that is unknown at compile time, it is not possible to make this transformation at compile time.

@No__t-0 操作码允许 IL 编译器以统一的方式对虚拟函数进行调用,而不管 ptr 是值类型还是引用类型。The constrained opcode allows IL compilers to make a call to a virtual function in a uniform way independent of whether ptr is a value type or a reference type. 尽管它适用于 @no__t 为泛型类型变量的情况,但 @no__t 前缀还适用于非泛型类型,并且可降低以隐藏值类型和引用之间的区别的语言生成虚拟调用的复杂性。各种.Although it is intended for the case where thisType is a generic type variable, the constrained prefix also works for nongeneric types and can reduce the complexity of generating virtual calls in languages that hide the distinction between value types and reference types.

使用 @no__t 的前缀还可以避免值类型出现潜在的版本控制问题。Using the constrained prefix also avoids potential versioning problems with value types. 如果未使用 @no__t 的前缀,则必须根据值类型是否重写 System.object 的方法来发出不同的 IL。If the constrained prefix is not used, different IL must be emitted depending on whether or not a value type overrides a method of System.Object. 例如,如果值类型 V 会重写对象 ToString ()方法,则会发出 @no__t 的 V.ToString() 指令;如果没有,则发出 @no__t 3 指令和 callvirt @no__t 指令。For example, if a value type V overrides the Object.ToString() method, a call V.ToString() instruction is emitted; if it does not, a box instruction and a callvirt Object.ToString() instruction are emitted. 如果稍后要删除重写,并且在后一种情况下,如果后来添加了替代,则可能会出现版本控制问题。A versioning problem can arise in the former case if the override is later removed, and in the latter case if an override is later added.

@No__t-0 前缀还可用于对值类型调用接口方法,因为实现接口方法的值类型方法可以使用 @no__t 更改。The constrained prefix can also be used for invocation of interface methods on value types, because the value type method implementing the interface method can be changed using a MethodImpl. 如果未使用 @no__t 0 前缀,则强制编译器选择要在编译时绑定到的值类型的方法。If the constrained prefix is not used, the compiler is forced to choose which of the value type's methods to bind to at compile time. 使用 @no__t 的前缀允许 MSIL 绑定到在运行时(而不是在编译时)实现接口方法的方法。Using the constrained prefix allows the MSIL to bind to the method that implements the interface method at run time, rather than at compile time.

以下 @no__t 0 方法重载可以使用 @no__t 操作码:The following Emit method overload can use the constrained opcode:

  • ILGenerator (OpCode,Type)ILGenerator.Emit(OpCode, Type)