X

C#修改程序集内部方法(给程序打补丁)制作模组的关键

XFEstudio 2026-02-01 13:18 93
编辑于 2026-02-01 13:22

使用Lib.Harmony给程序集打补丁

一、安装 HarmonyLib

NuGet 安装:

dotnet add package Lib.Harmony

或在 VS 的 NuGet 管理器里搜 Lib.Harmony


二、最小可用示例(核心流程)

1️⃣ 假设有一个原始类(第三方 / 你自己的都行)

public class Calculator
{
    public int Add(int a, int b)
    {
        Console.WriteLine("原始 Add 被调用");
        return a + b;
    }
}

2️⃣ 创建 Harmony Patch 类

using HarmonyLib;

[HarmonyPatch(typeof(Calculator))]
[HarmonyPatch(nameof(Calculator.Add))]
public class CalculatorPatch
{
    // Prefix:方法执行前
    static void Prefix(int a, int b)
    {
        Console.WriteLine($"Prefix:a={a}, b={b}");
    }

    // Postfix:方法执行后
    static void Postfix(int __result)
    {
        Console.WriteLine($"Postfix:结果={__result}");
    }
}

⚠️ 关键点:

  • __result 是 Harmony 的魔法参数
  • 参数名必须严格匹配
  • 方法必须是 static

3️⃣ 在程序启动时应用 Patch

using HarmonyLib;

class Program
{
    static void Main()
    {
        var harmony = new Harmony("com.xfe.demo.patch");
        harmony.PatchAll();

        var calc = new Calculator();
        Console.WriteLine(calc.Add(2, 3));
    }
}

输出顺序:

Prefix:a=2, b=3
原始 Add 被调用
Postfix:结果=5
5

三、常见 Patch 类型(重点)

🔹 1. Prefix(最常用)

  • 返回 bool
  • false = 跳过原方法
static bool Prefix(ref int __result)
{
    __result = 999;
    return false; // 原方法不会执行
}

👉 直接“接管”原方法


🔹 2. Postfix

  • 修改返回值
static void Postfix(ref int __result)
{
    __result *= 2;
}

🔹 3. Transpiler(高级 / IL 级)

👉 直接改 IL 指令

using System.Reflection.Emit;

static IEnumerable<CodeInstruction> Transpiler(
    IEnumerable<CodeInstruction> instructions)
{
    foreach (var ins in instructions)
    {
        yield return ins;
    }
}

⚠️ 这个一般只在:

  • 没法用 Prefix/Postfix
  • 必须精确改某几行逻辑时用

四、Patch 私有 / 静态 / 重载方法

🔹 私有方法

[HarmonyPatch(typeof(MyClass), "PrivateMethod")]

🔹 重载方法(很重要)

[HarmonyPatch(typeof(MyClass))]
[HarmonyPatch("Do")]
[HarmonyPatch(new Type[] { typeof(int), typeof(string) })]

🔹 静态方法

Patch 写法一样,不用特殊处理


五、常用 Harmony “魔法参数”速查表

参数名 作用
__instance 当前对象实例
__result 返回值
__state Prefix → Postfix 传递数据
__originalMethod 原始 MethodInfo
__args 所有参数数组

示例:Prefix → Postfix 共享数据

static void Prefix(ref long __state)
{
    __state = Stopwatch.GetTimestamp();
}

static void Postfix(long __state)
{
    Console.WriteLine("耗时:" + __state);
}

六、只 Patch 指定方法(不 PatchAll)

var harmony = new Harmony("xfe.single.patch");

var original = AccessTools.Method(
    typeof(Calculator), "Add");

var prefix = new HarmonyMethod(
    typeof(CalculatorPatch), "Prefix");

harmony.Patch(original, prefix);

七、常见坑(血泪总结)

❌ 方法签名不匹配 → 不生效

👉 参数名、类型、ref 都要对

❌ 忘了 static

👉 Patch 方法必须是 static

❌ Patch 顺序问题

👉 多个 Harmony 同时 Patch,用:

[HarmonyPriority(Priority.High)]
0 条回复
暂无回复,快来抢沙发吧!
发表回复
登录 后发表回复。