C# Harmony补丁开发中如何使用internal类作为补丁方法参数
问题原因
你遇到的编译错误和声明位置没有关系,核心是两个基础认知错误:
- C#是静态类型语言,方法参数的类型必须是编译阶段就能被编译器识别的类型定义,你写的
MyInternal是一个运行时通过反射拿到的Type类型的变量,它本身不是类型定义,编译器只会把参数位置写的MyInternal当成一个未定义的类型名去查找,自然会报找不到的错误,不管你把这个变量挪到类外还是命名空间下都解决不了问题。 - 你引用的游戏程序集中的
internal类型,本身就不允许外部程序集在编译时直接访问,哪怕你引入了对应命名空间也没用,这是C#的访问控制规则决定的。
解决方案
用Harmony写这类补丁时,不需要在编译时拿到目标internal类型的定义,按下面的写法实现即可:
- 用
object类型作为对应位置的参数类型接收传入的internal实例:Harmony注入参数时不校验编译时的参数类型声明,只要参数位置和注入规则匹配,会直接把原方法的真实实参传入,不会有类型转换错误。 - 提前把反射拿到的internal类型缓存为静态只读字段,后续操作实例时通过反射或者
dynamic访问成员即可。
参考代码如下:
using System; using System.Reflection; using HarmonyLib; using namespacesFromGame; namespace MyMod { [HarmonyPatch(typeof(GameClass))] class MyPatch { // 缓存internal类型,避免每次执行补丁都重复反射查找 private static readonly Type GameInternalType = typeof(GameClass).Assembly.GetType("GameInternal"); // 按Harmony的补丁规则写方法签名,internal类型的参数直接用object接 public static bool MethodPatch(GameClass __instance, /* 其他你需要的参数 */ object myInternal /* 其余参数 */) { // 操作实例的两种常用方式: // 方式1:用dynamic,写法简洁,注意成员名要和原类一致,写错会在运行时报错 // dynamic internalInstance = myInternal; // var targetValue = internalInstance.xxx字段/属性; // internalInstance.xxx方法(参数); // 方式2:用缓存的Type走反射访问,可控性更高 // var targetField = GameInternalType.GetField("xxx字段名", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); // var targetValue = targetField.GetValue(myInternal); // 你的补丁业务逻辑 return true; // 按自身需求决定是否继续执行原方法 } } }
注意事项
不要尝试在自己的代码里手动定义和游戏内GameInternal同命名空间、同名的类来模拟类型:不同程序集中加载的同命名空间同名类型在运行时是完全独立的两个类型,Harmony传参时会抛出类型转换异常,完全没有必要。
内容的提问来源于stack exchange,提问作者GeneralMike
相关产品推荐
相关产品推荐

