提问人:user2771324 提问时间:9/24/2022 最后编辑:user2771324 更新时间:9/24/2022 访问量:1031
如何在泛型类的静态非泛型方法上进行.NET运行时方法修补?(Harmony 或 MonoMod)
How to do .NET runtime method patch on generic class's static non-generic method? (Harmony or MonoMod)
问:
在此示例中,我想修补 .
如何使用 Harmony 或 MonoMod 完成它?PatchTarget.QSingleton\<T\>.get_Instance()
和谐:
“未处理的异常。System.NotSupportedException:指定的方法 不受支持。
单模组:
“未处理的异常。System.ArgumentException:给定的泛型 实例化无效。
代码片段:(可用dotnetfiddle.net
)
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
namespace PatchTarget {
public abstract class QSingleton<T> where T : QSingleton<T>, new() {
protected static T instance = null; protected QSingleton() { }
public static T Instance { get {
if (instance == null) {
instance = new T();
Console.Write($"{typeof(T).Name}.Instance: impl=QSingleton");
}
return instance;
} }
}
}
namespace Patch {
public class TypeHelper<T> where T : PatchTarget.QSingleton<T>, new() {
public static T InstanceHack() {
Console.Write($"{typeof(T).Name}.Instance: impl=InstanceHack");
return null;
}
}
public static class HarmonyPatch {
public static Harmony harmony = new Harmony("Try");
public static void init() {
var miOriginal = AccessTools.Property(typeof(PatchTarget.QSingleton<>), "Instance").GetMethod;
var miHack = AccessTools.Method(typeof(TypeHelper<>), "InstanceHack");
harmony.Patch(miOriginal, prefix: new HarmonyMethod(miHack));
}
}
public static class MonoModPatch {
public static MonoMod.RuntimeDetour.Detour sHook;
public static void init() {
var miOriginal = AccessTools.Property(typeof(PatchTarget.QSingleton<>), "Instance").GetMethod;
var miHack = AccessTools.Method(typeof(TypeHelper<>), "InstanceHack");
sHook = new MonoMod.RuntimeDetour.Detour(miOriginal, miHack);
}
}
}
class Program {
public static void Main() {
Patch.HarmonyPatch.init();
// Patch.MonoModPatch.init();
Console.WriteLine($"done");
}
}
答:
0赞
user2771324
9/24/2022
#1
经过一番反复试验,我得到了一些工作,但不是背后的原因。
- Harmony 和 MonoMod.RuntimeDetour 都可以挂接 typeof(QSingleton<SampleA>)。GetMethod(),但不是 typeof(QSingleton<>)。GetMethod() 中。
- 和谐输出出乎意料。
- Harmony 属性注释似乎不起作用。
- 生成 IL 似乎毫无用处,因为泛型可能缺少 TypeSpec。
问题:
- QSingleton<>有什么区别。实例和 QSingleton<SampleA>。示例中的实例?
我猜<>。Instance 是 MethodDef,而 <SampleA>。实例的数据类型为 TypeSpec.MemberRef。 - 为什么 Harmony/MonoMod.RuntimeDetour 需要 TypeSpec.MemberRef?用于生成重定向存根?
- 是否可以在 Harmony 下修复钩子?
- 如果 TypeSpec 已经存在,Harmony/MonoMod 可以生成“ldtoken <TypeSpec>”吗?
- Harmony/MonoMod 能否为泛型动态生成必要的 TypeSpec?
代码片段:(可使用 dotnetfiddle.net 运行)
using System;
using HarmonyLib;
namespace PatchTarget {
public abstract class QSingleton<T> where T : QSingleton<T>, new() {
protected static T instance = null; protected QSingleton() { }
public static T Instance { get {
if (instance == null) {
instance = new T();
Console.WriteLine($"{typeof(T).Name}.Instance: impl=QSingleton");
}
return instance;
} }
}
public class SampleA : QSingleton<SampleA> {
public SampleA() { Console.WriteLine("SampleA ctor"); }
}
public class SampleB : QSingleton<SampleB> {
public SampleB() { Console.WriteLine("SampleB ctor"); }
}
}
namespace Patch {
public class TypeHelper<T> where T : PatchTarget.QSingleton<T>, new() {
public static T InstanceHack() {
Console.WriteLine($"{typeof(T).Name}.Instance: impl=InstanceHack");
return null;
}
// For Harmony as Prefix, but attribute does not work.
public static bool InstanceHackPrefix(T __result) {
Console.WriteLine($"{typeof(T).Name}.Instance: impl=InstanceHack");
__result = null;
return false;
}
}
public static class HarmonyPatch {
public static Harmony harmony = new Harmony("Try");
public static void init() {
// Attribute does not work.
// Transpiler does not work because the lack of TypeSpec to setup generic parameters.
var miOriginal = AccessTools.Property(typeof(PatchTarget.QSingleton<PatchTarget.SampleB>), "Instance").GetMethod;
var miHack = AccessTools.Method(typeof(TypeHelper<PatchTarget.SampleB>), "InstanceHackPrefix");
harmony.Patch(miOriginal, prefix: new HarmonyMethod(miHack));
}
}
public static class MonoModPatch {
public static MonoMod.RuntimeDetour.Detour sHook;
public static void init() {
var miOriginal = AccessTools.Property(typeof(PatchTarget.QSingleton<PatchTarget.SampleB>), "Instance").GetMethod;
var miHack = AccessTools.Method(typeof(TypeHelper<PatchTarget.SampleB>), "InstanceHack");
sHook = new MonoMod.RuntimeDetour.Detour(miOriginal, miHack);
}
}
}
class Program {
public static void Main() {
_ = PatchTarget.SampleA.Instance;
// MonoMod works (replaces globally).
// Harmony hooks, but in an expected way (T becomes SampleB, not 1st generic type parameter).
// try { Patch.HarmonyPatch.init(); } catch (Exception e) { Console.WriteLine($"Harmony error: {e.ToString()}"); }
try { Patch.MonoModPatch.init(); } catch (Exception e) { Console.WriteLine($"MonoMod error: {e.ToString()}"); }
_ = PatchTarget.SampleB.Instance;
_ = PatchTarget.SampleA.Instance;
Console.WriteLine($"done");
}
}
MonoMod.RuntimeDetour 输出:(按预期工作)
SampleA.Instance:impl=QSingleton
SampleB.Instance:impl=InstanceHack SampleA.Instance:impl=InstanceHack
和声输出:(破碎<T>)
SampleA.Instance:impl=QSingleton
SampleB.Instance:impl=InstanceHack SampleB.Instance:impl=InstanceHack
上一个:缺少 R 的 Harmony 包
评论