OpCodes.Call 字段


调用由传递的方法说明符指示的方法。Calls the method indicated by the passed method descriptor.

public: static initonly System::Reflection::Emit::OpCode Call;
public static readonly System.Reflection.Emit.OpCode Call;
 staticval mutable Call : System.Reflection.Emit.OpCode
Public Shared ReadOnly Call 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
28 < T >28 < T > 调用 methodDesccall methodDesc 调用 methodDesc 所描述的方法。Call the method described by methodDesc.

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

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

  2. 从堆栈中弹出 arg1 到 @no__t 的方法参数;使用这些参数执行方法调用,并将控件传输到方法说明符所引用的方法。Method arguments arg1 through argN are popped from the stack; the method call is performed with these arguments and control is transferred to the method referred to by the method descriptor. 完成后,调用方方法将生成一个返回值,并将其发送给调用方。When complete, a return value is generated by the callee method and sent to the caller.

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

@No__t-0 指令调用通过指令传递的方法说明符指示的方法。The call instruction calls the method indicated by the method descriptor passed with the instruction. 方法描述符是一种元数据标记,用于指示要调用的方法,以及要传递到该方法的堆栈上的参数的数量、类型和顺序,以及要使用的调用约定。The method descriptor is a metadata token that indicates the method to call and the number, type, and order of the arguments that have been placed on the stack to be passed to that method as well as the calling convention to be used. @No__t-0 指令前面可以跟 tailTailcall)前缀指令,以指定在传输控制之前应释放当前方法状态。The call instruction can be immediately preceded by a tail (Tailcall) prefix instruction to specify that the current method state should be released before transferring control. 如果调用将控制转移到比源方法更高的信任方法,则不会释放堆栈帧。If the call transfers control to a method of higher trust than the origin method, the stack frame is not released. 相反,执行将以无提示方式继续,就好像尚未提供 tailInstead, the execution continues silently as if the tail had not been supplied. 元数据标记携带足够的信息来确定调用是静态方法、实例方法、虚方法还是全局函数。The metadata token carries sufficient information to determine whether the call is to a static method, an instance method, a virtual method, or a global function. 在所有这些情况下,均从方法描述符完全确定目标地址(与此与调用虚拟方法的 @no__t 0 指令相比,其中,目标地址也依赖于实例引用的运行时类型)推送到 Callvirt 之前)。In all of these cases the destination address is determined entirely from the method descriptor (contrast this with the Callvirt instruction for calling virtual methods, where the destination address also depends upon the runtime type of the instance reference pushed before the Callvirt).

自变量以从左到右的顺序放置在堆栈上。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. 有三个重要的特殊情况:There are three important special cases:

  1. 对实例(或虚拟)方法的调用必须将该实例引用推送到任何用户可见参数之前。Calls to an instance (or virtual) method must push that instance reference before any of the user-visible arguments. 实例引用不得为空引用。The instance reference must not be a null reference. 在元数据中携带的签名不包含 this 指针的参数列表中的条目;相反,它使用一个位来指示方法是否要求传递 this 指针。The signature carried in the metadata does not contain an entry in the parameter list for the this pointer; instead, it uses a bit to indicate whether the method requires passing the this pointer.

  2. 使用 call (而不是 callvirt)调用虚拟方法是有效的;这表示使用方法指定的类(而不是从所调用的对象动态指定)解析方法。It is valid to call a virtual method using call (rather than callvirt); this indicates that the method is to be resolved using the class specified by method rather than as specified dynamically from the object being invoked.

  3. 请注意,可以使用 @no__t 或 @no__t 指令调用委托的 @no__t 0 方法。Note that a delegate's Invoke method can be called with either the call or callvirt instruction.

如果系统安全不允许调用方访问调用的方法,则可能会引发 SecurityExceptionSecurityException may be thrown if system security does not grant the caller access to the called method. 当 Microsoft 中间语言(MSIL)指令转换为本机代码而不是运行时,可能会进行安全检查。The security check may occur when the Microsoft Intermediate Language (MSIL) instructions are converted to native code rather than at run time.


当在值类型上调用 System.object 的方法时,请考虑将 constrained 前缀与 callvirt 指令一起使用,而不是发出 @no__t 的指令。When calling methods of System.Object on value types, consider using the constrained prefix with the callvirt instruction instead of emitting a call 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.

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

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

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


varargs 调用提供 EmitCall 方法。The EmitCall method is provided for varargs calls. 使用 Emit 方法进行正常调用。Use the Emit method for normal calls.