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

C#中用Mono.Cecil调用其他程序集父类方法的问题(Unity场景)

解决Unity中Mono.Cecil无法解析UnityEngine.CoreModule的问题

问题场景

在Unity项目中,使用Mono.Cecil对自定义脚本(继承自MonoBehaviour)做IL注入,尝试调用父类MonoBehaviour的GetComponent方法时,运行时抛出AssemblyResolutionException,提示无法解析UnityEngine.CoreModule程序集。

初始实现代码

var processor = hookMethod.Body.GetILProcessor();

// 查找基类(MonoBehaviour)中的GetComponent方法
var getComponentMethod = typeDefinition.BaseType.Resolve().Methods.First(it => it.Name == "GetComponent");

var firstInstruction = hookMethod.Body.Instructions[0];

var thisCall = processor.Create(OpCodes.Ldarg_0);
var methodCall = processor.Create(OpCodes.Call, getComponentMethod);

processor.InsertBefore(firstInstruction, methodCall);
processor.InsertBefore(methodCall, thisCall);

抛出的错误信息

AssemblyResolutionException: Failed to resolve assembly: 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
Mono.Cecil.BaseAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name, Mono.Cecil.ReaderParameters parameters) (at <6f6cad7a41144167841153769a3850ff>:0)
Mono.Cecil.BaseAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name) (at <6f6cad7a41144167841153769a3850ff>:0)
Mono.Cecil.DefaultAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name) (at <6f6cad7a41144167841153769a3850ff>:0)
Mono.Cecil.MetadataResolver.Resolve (Mono.Cecil.TypeReference type) (at <6f6cad7a41144167841153769a3850ff>:0)
Mono.Cecil.ModuleDefinition.Resolve (Mono.Cecil.TypeReference type) (at <6f6cad7a41144167841153769a3850ff>:0)
Mono.Cecil.TypeReference.Resolve () (at <6f6cad7a41144167841153769a3850ff>:0)
MissingBracket.Injection.Editor.InjectionProcessor.Process (Mono.Cecil.TypeDefinition typeDefinition, Mono.Cecil.ModuleDefinition moduleDefinition, System.Boolean& modified) (at Assets/Plugins/Missing Bracket/Injection/Editor/InjectionProcessor.cs:33)
MissingBracket.Common.Editor.Weaver.Weave (System.Reflection.Assembly[] assemblies, Mono.Cecil.AssemblyDefinition assemblyDefinition, Mono.Cecil.IAssemblyResolver asmResolver, System.Boolean& modified) (at Assets/Plugins/Missing Bracket/Common/Editor/Weaver/Weaver.cs:35)
MissingBracket.Common.Editor.WeaverExecutor.WeaveFromFile (System.String assemblyPath) (at Assets/Plugins/Missing Bracket/Common/Editor/Weaver/WeaverExecutor.cs:52)
MissingBracket.Common.Editor.WeaverExecutor.OnCompilationFinished (System.String assemblyPath, UnityEditor.Compilation.CompilerMessage[] messages) (at Assets/Plugins/Missing Bracket/Common/Editor/Weaver/WeaverExecutor.cs:40)
UnityEditor.Compilation.CompilationPipeline+<>c.<SubscribeToEvents>b__26_3 (UnityEditor.Scripting.ScriptCompilation.ScriptAssembly scriptAssembly, UnityEditor.Compilation.CompilerMessage[] messages) (at <97436df440ca462884c5332c1d8ebbe7>:0)
UnityEditor.Scripting.ScriptCompilation.EditorCompilationInterface:TickCompilationPipeline(EditorScriptCompilationOptions, BuildTargetGroup, BuildTarget, Int32, String[], Boolean)

尝试过的无效代码

var methodRef = typeDefinition.BaseType.Module.ImportReference(typeDefinition.BaseType).Resolve();
var getComponentMethod = methodRef.Methods.First(it => it.Name == "GetComponent");

解决方案

错误根源是Mono.Cecil的默认程序集解析器不知道Unity核心程序集的存放路径,需要手动配置解析器的搜索目录,同时修正IL指令的调用方式。

步骤1:配置程序集解析器

在加载目标程序集之前,给DefaultAssemblyResolver添加Unity引擎程序集的搜索路径:

var resolver = new DefaultAssemblyResolver();
// 添加Unity核心程序集目录(根据Unity版本调整路径)
var unityManagedPath = Path.Combine(EditorApplication.applicationContentsPath, "Managed");
resolver.AddSearchDirectory(unityManagedPath);
// 部分Unity版本需要额外添加子目录
var unityEnginePath = Path.Combine(unityManagedPath, "UnityEngine");
resolver.AddSearchDirectory(unityEnginePath);

// 加载程序集时传入配置好的解析器
var readerParams = new ReaderParameters { AssemblyResolver = resolver };
var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath, readerParams);

步骤2:正确引用并调用目标方法

避免不必要的程序集解析,同时注意虚方法的调用指令:

var processor = hookMethod.Body.GetILProcessor();

// 获取MonoBehaviour类型引用
var baseTypeRef = typeDefinition.BaseType;
// 匹配正确的GetComponent重载(这里选非泛型、接收System.Type参数的版本)
var getComponentMethodDef = baseTypeRef.Resolve().Methods.First(
    m => m.Name == "GetComponent" 
         && m.Parameters.Count == 1 
         && m.Parameters[0].ParameterType.FullName == "System.Type");

// 将方法定义导入到当前模块
var getComponentMethodRef = typeDefinition.Module.ImportReference(getComponentMethodDef);

var firstInstruction = hookMethod.Body.Instructions[0];

// 构建IL指令:先加载this,再调用虚方法
var ldarg0 = processor.Create(OpCodes.Ldarg_0);
// 注意:MonoBehaviour.GetComponent是虚方法,必须用Callvirt而非Call
var callMethod = processor.Create(OpCodes.Callvirt, getComponentMethodRef);

processor.InsertBefore(firstInstruction, callMethod);
processor.InsertBefore(callMethod, ldarg0);

关键注意事项

  • 虚方法调用:GetComponent是虚方法,必须使用OpCodes.Callvirt,否则会触发运行时错误。
  • 重载匹配:GetComponent有多个重载(泛型、非泛型),要根据实际需求筛选对应签名的方法。
  • 路径适配:不同Unity版本的程序集存放路径可能有差异,需根据项目使用的版本调整搜索目录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:50:59