如何用Harmony或MonoMod对泛型类的静态非泛型方法做.NET运行时补丁?
如何用Harmony或MonoMod补丁泛型单例的
get_Instance方法 你遇到的两个异常本质原因一致:直接尝试补丁未实例化的泛型方法定义(即QSingleton<>的get_Instance),而Harmony和MonoMod都不支持直接操作泛型定义,必须针对具体的泛型实例(比如QSingleton<MyConcreteSingleton>)来打补丁,或者通过反射扫描批量处理所有子类。
Harmony 解决方案
1. 针对具体泛型实例打补丁
如果你明确知道要补丁的具体单例类型(比如MySingleton),直接获取该实例化后的属性get方法即可:
namespace Patch { public static class HarmonyPatch { public static Harmony harmony = new Harmony("Try"); public static void init() { // 替换为你实际要补丁的具体单例类型 Type concreteSingletonType = typeof(MySingleton); // 获取该具体类型的Instance属性get方法 MethodInfo miOriginal = AccessTools.Property(concreteSingletonType, "Instance").GetMethod; // 生成对应的TypeHelper<T>实例方法 MethodInfo miHack = AccessTools.Method( typeof(TypeHelper<>).MakeGenericType(concreteSingletonType), "InstanceHack" ); harmony.Patch(miOriginal, prefix: new HarmonyMethod(miHack)); } } } // 测试用的具体单例类 public class MySingleton : PatchTarget.QSingleton<MySingleton> { }
2. 自动批量补丁所有QSingleton子类
如果需要自动处理程序集中所有继承自QSingleton<T>的具体单例类型,可以通过反射扫描实现:
namespace Patch { public static class HarmonyPatch { public static Harmony harmony = new Harmony("Try"); public static void init() { Type qSingletonGenericDef = typeof(PatchTarget.QSingleton<>); // 扫描当前程序集所有符合条件的类型 foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) { // 过滤:非抽象类、基类是QSingleton<T>的泛型实例 if (!type.IsAbstract && type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == qSingletonGenericDef) { MethodInfo miOriginal = AccessTools.Property(type, "Instance").GetMethod; MethodInfo miHack = AccessTools.Method( typeof(TypeHelper<>).MakeGenericType(type), "InstanceHack" ); harmony.Patch(miOriginal, prefix: new HarmonyMethod(miHack)); } } } } }
MonoMod 解决方案
MonoMod的处理逻辑和Harmony一致,同样需要针对具体泛型实例:
1. 针对具体泛型实例打补丁
namespace Patch { public static class MonoModPatch { public static MonoMod.RuntimeDetour.Detour sHook; public static void init() { Type concreteSingletonType = typeof(MySingleton); MethodInfo miOriginal = AccessTools.Property(concreteSingletonType, "Instance").GetMethod; MethodInfo miHack = AccessTools.Method( typeof(TypeHelper<>).MakeGenericType(concreteSingletonType), "InstanceHack" ); sHook = new MonoMod.RuntimeDetour.Detour(miOriginal, miHack); } } } // 测试用的具体单例类 public class MySingleton : PatchTarget.QSingleton<MySingleton> { }
2. 自动批量补丁所有QSingleton子类
namespace Patch { public static class MonoModPatch { public static List<MonoMod.RuntimeDetour.Detour> sHooks = new List<MonoMod.RuntimeDetour.Detour>(); public static void init() { Type qSingletonGenericDef = typeof(PatchTarget.QSingleton<>); foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) { if (!type.IsAbstract && type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == qSingletonGenericDef) { MethodInfo miOriginal = AccessTools.Property(type, "Instance").GetMethod; MethodInfo miHack = AccessTools.Method( typeof(TypeHelper<>).MakeGenericType(type), "InstanceHack" ); sHooks.Add(new MonoMod.RuntimeDetour.Detour(miOriginal, miHack)); } } } } }
原代码报错原因说明
- Harmony的
System.NotSupportedException:Harmony不支持直接补丁泛型方法定义(QSingleton<>),必须针对实例化后的具体泛型方法。 - MonoMod的
System.ArgumentException:MonoMod的Detour要求目标方法是具体的、非泛型定义的方法,传递未实例化的泛型方法会触发参数验证失败。
内容的提问来源于stack exchange,提问作者user2771324
相关产品推荐
相关产品推荐

