OpCodes.Callvirt 字段


对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。Calls a late-bound method on an object, pushing the return value onto the evaluation stack.

public: static initonly System::Reflection::Emit::OpCode Callvirt;
public static readonly System.Reflection.Emit.OpCode Callvirt;
 staticval mutable Callvirt : System.Reflection.Emit.OpCode
Public Shared ReadOnly Callvirt 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
6F < T >6F < T > callvirt methodcallvirt method 调用与 @no__t 关联的特定方法。Calls a specific method associated with obj.

堆栈转换行为顺序如下:The stack transitional behavior, in sequential order, is:

  1. obj 的对象引用推送到堆栈上。An object reference obj is pushed onto the stack.

  2. 方法参数 arg1argN 将被推送到堆栈上。Method arguments arg1 through argN are pushed onto the stack.

  3. 方法参数 arg1argN,并且从堆栈中弹出对象引用 obj;使用这些参数执行方法调用,并将控件传输到方法元数据标记所引用 @no__t 3 中的方法。Method arguments arg1 through argN and the object reference obj are popped from the stack; the method call is performed with these arguments and control is transferred to the method in obj referred to by the method metadata token. 完成后,调用方方法将生成一个返回值,并将其发送给调用方。When complete, a return value is generated by the callee method and sent to the caller.

  4. 将返回值推送到堆栈上。The return value is pushed onto the stack.

@No__t-0 指令对对象调用后期绑定方法。The callvirt instruction calls a late-bound method on an object. 也就是说,根据 @no__t 的运行时类型(而不是方法指针中的编译时类)选择方法。That is, the method is chosen based on the runtime type of obj rather than the compile-time class visible in the method pointer. Callvirt 可用于调用虚拟方法和实例方法。Callvirt can be used to call both virtual and instance methods. @No__t-0 指令前面可以跟 tailTailcall)前缀,以指定在传输控制之前应释放当前堆栈帧。The callvirt instruction may be immediately preceded by a tail (Tailcall) prefix to specify that the current stack frame should be released before transferring control. 如果调用会将控制传输到比原始方法更高的信任方法,则不会释放堆栈帧。If the call would transfer control to a method of higher trust than the original method the stack frame will not be released.

方法元数据标记提供要调用的方法的名称、类和签名。The method metadata token provides the name, class and signature of the method to call. 与 @no__t 关联的类是它作为其实例的类。The class associated with obj is the class of which it is an instance. 如果类定义了与指定方法名称和签名匹配的非静态方法,则会调用此方法。If the class defines a non-static method that matches the indicated method name and signature, this method is called. 否则,会按顺序检查此类的基类链中的所有类。Otherwise all classes in the base class chain of this class are checked in order. 如果未找到任何方法,则是错误的。It is an error if no method is found.

@no__t 在调用方法之前,从计算堆栈中弹出对象和关联参数。Callvirt pops the object and the associated arguments off the evaluation stack before calling the method. 如果该方法具有返回值,则在方法完成后将其推送到堆栈上。If the method has a return value, it is pushed on the stack upon method completion. 在被调用方方,@no__t 的参数作为参数0访问,arg1 作为参数1,依此类推。On the callee side, the obj parameter is accessed as argument 0, arg1 as argument 1, and so on.

自变量以从左到右的顺序放置在堆栈上。The arguments are placed on the stack in left-to-right order. 也就是说,第一个参数是计算并放置在堆栈上,然后是第三个参数,然后是第三个参数,直到所有必需的参数按降序排列。That is, the first argument is computed and placed on the stack, then the second argument, then the third, until all necessary arguments are atop the stack in descending order. 实例引用 obj (始终需要用于 callvirt)必须推送到任何用户可见参数之前。The instance reference obj (always required for callvirt) must be pushed before any of the user-visible arguments. 签名(包含在元数据标记中)不需要包含在此指针的参数列表中的条目。The signature (carried in the metadata token) need not contain an entry in the parameter list for the this pointer.

请注意,还可以使用 @no__t 0 指令来调用虚拟方法。Note that a virtual method can also be called using the Call instruction.

如果在与 obj 或其任何基类关联的类中找不到具有指定名称和签名的非静态方法,则会引发 MissingMethodExceptionMissingMethodException is thrown if a non-static method with the indicated name and signature could not be found in the class associated with obj or any of its base classes. 当 Microsoft 中间语言(MSIL)指令转换为本机代码而不是运行时,通常会检测到此情况。This is typically detected when Microsoft Intermediate Language (MSIL) instructions are converted to native code, rather than at runtime.

如果 obj 为 null,则会引发 NullReferenceExceptionNullReferenceException is thrown if obj is null.

如果系统安全不向调用方授予对所调用方法的访问权限,则会引发 SecurityExceptionSecurityException is thrown if system security does not grant the caller access to the called method. 当 CIL 转换为本机代码而不是运行时,可能会进行安全检查。The security check may occur when the CIL is converted to native code rather than at run time.


当在值类型上调用 System.object 的方法时,请考虑将 @no__t 的前缀与 callvirt 指令一起使用。When calling methods of System.Object on value types, consider using the constrained prefix with the callvirt instruction. 这就不必发出不同的 IL,具体取决于值类型是否重写方法,避免出现潜在的版本控制问题。This removes the need to emit different IL depending on whether or not the value type overrides the method, avoiding a potential versioning problem. 当对值类型调用接口方法时,请考虑使用 constrained 前缀,因为实现接口方法的值类型方法可以使用 MethodImpl 进行更改。Consider using the constrained prefix when invoking interface methods on value types, since the value type method implementing the interface method can be changed using a MethodImpl. @No__t 操作码中更详细地介绍了这些问题。These issues are described in more detail in the Constrained opcode.

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

  • ILGenerator (操作码,MethodInfo)ILGenerator.Emit(OpCode, MethodInfo)

  • ILGenerator.EmitCall(OpCode, MethodInfo, Type[])ILGenerator.EmitCall(OpCode, MethodInfo, Type[])