You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Mono.Cecil注入构造方法调用触发InvalidProgramException异常

问题描述

使用Mono.Cecil向构造函数注入方法调用时,抛出以下错误:

InvalidProgramException: Invalid IL code in Networking.ServerController:.ctor (): IL_0028: callvirt  0x0600017f

操作逻辑:针对每个stfld指令,注入父类NetworkBehaviour中的LocalNetworkVariableChange方法调用,传入字段名和装箱后的字段值。该方法定义:

protected void LocalNetworkVariableChange(string variableName, object value) {
  // 无论此处编写什么代码都会失败
}

注入前构造函数IL:

IL_0000: ldarg.0
IL_0001: newobj System.Void System.Collections.Generic.Dictionary`2<System.UInt16,Networking.ServerController/ConnectedPlayer>::.ctor()
IL_0006: stfld System.Collections.Generic.Dictionary`2<System.UInt16,Networking.ServerController/ConnectedPlayer> Networking.ServerController::_connectedPlayersByClientId
IL_000b: ldarg.0
IL_000c: newobj System.Void System.Collections.Generic.Dictionary`2<Util.NuID,Networking.ServerController/ConnectedPlayer>::.ctor()
IL_0011: stfld System.Collections.Generic.Dictionary`2<Util.NuID,Networking.ServerController/ConnectedPlayer> Networking.ServerController::_connectedPlayersByPlayerId
IL_0016: ldarg.0
IL_0017: call System.Void Networking.PeerController`1<Networking.ServerController>::.ctor()
IL_001c: nop
IL_001d: ret

最终生成的IL代码:

.method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       62 (0x3e)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  newobj     instance void [netstandard]System.Collections.Generic.Dictionary`2<uint16,class Networking.ServerController/ConnectedPlayer>::.ctor()
    IL_0006:  stfld      [netstandard]System.Collections.Generic.Dictionary`2<uint16,class Networking.ServerController/ConnectedPlayer> Networking.ServerController::_connectedPlayersByClientId
    IL_000b:  ldarg.0
    IL_000c:  newobj     instance void [netstandard]System.Collections.Generic.Dictionary`2<class Util.NuID,class Networking.ServerController/ConnectedPlayer>::.ctor()
    IL_0011:  stfld      [netstandard]System.Collections.Generic.Dictionary`2<class Util.NuID,class Networking.ServerController/ConnectedPlayer> Networking.ServerController::_connectedPlayersByPlayerId
    IL_0016:  ldarg.0
    IL_0017:  call       instance void class Networking.PeerController`1<class Networking.ServerController>::.ctor()
    IL_001c:  nop
    IL_001d:  ldarg.0
    IL_001e:  ldstr      "_connectedPlayersByClientId"
    IL_0023:  ldfld      [netstandard]System.Collections.Generic.Dictionary`2<uint16,class Networking.ServerController/ConnectedPlayer> Networking.ServerController::_connectedPlayersByClientId
    IL_0028:  callvirt   instance void Networking.NetworkBehaviour::LocalNetworkVariableChange(string,
                                                                                               object)
    IL_002d:  ldarg.0
    IL_002e:  ldstr      "_connectedPlayersByPlayerId"
    IL_0033:  ldfld      [netstandard]System.Collections.Generic.Dictionary`2<class Util.NuID,class Networking.ServerController/ConnectedPlayer> Networking.ServerController::_connectedPlayersByPlayerId
    IL_0038:  callvirt   instance void Networking.NetworkBehaviour::LocalNetworkVariableChange(string,
                                                                                               object)
    IL_003d:  ret
  } // end of method ServerController::.ctor

相关字段定义:

[NetworkVariable(SyncOnChange = false)]
private readonly Dictionary<ushort, ConnectedPlayer> _connectedPlayersByClientId = new
  Dictionary<ushort, ConnectedPlayer>();
[NetworkVariable(SyncOnChange = false)]
private readonly Dictionary<NuID, ConnectedPlayer> _connectedPlayersByPlayerId = new
  Dictionary<NuID, ConnectedPlayer>();
异常原因
  1. 构造阶段虚方法表未初始化完成
    C#构造函数执行时,子类会先初始化自身字段,再调用父类构造函数。你注入的方法调用虽然在PeerController构造之后,但此时整个对象的虚方法表(vtable)还未完全初始化。callvirt指令依赖vtable查找方法实现,构造过程中对象状态不稳定,导致指令无法找到有效方法入口,触发异常。

  2. 错误使用callvirt指令
    LocalNetworkVariableChange是父类的非虚方法(未标记virtual/override),不需要虚调度。callvirt会先检查对象引用有效性并通过vtable查找方法,而构造阶段的对象状态无法通过这种检查。应该用call指令直接调用父类方法,跳过虚方法表查找。

解决方法

将注入的callvirt指令替换为call指令:

// 替换前
IL_0028:  callvirt   instance void Networking.NetworkBehaviour::LocalNetworkVariableChange(string, object)

// 替换后
IL_0028:  call       instance void Networking.NetworkBehaviour::LocalNetworkVariableChange(string, object)

同时保持注入代码在父类构造函数执行之后的位置,确保父类基础逻辑已完成。

内容的提问来源于stack exchange,提问作者Sebastian Barth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:46:59