前篇簡單介紹了 Harmony Library,這篇開始介紹補丁的實作,因為 Prefix 與 Postfix 常常會搭配,所以就併在一起說明。
功能
Prefix 和 Postfix 搭配起來某種程度上很類似 Proxy Pattern 的作用;Prefix 作用在原始方法執行之前,而 Postfix 作用在原始方法執行之後。
Prefix — Prefix 會在原始方法執行前被呼叫,你可以把它想像成一個「守門員」。
- 在原始方法執行前插入邏輯
- 修改傳入的參數
- 回傳 false 直接跳過原始方法
- 提前設定回傳值
Postfix — Postfix 會在原始方法執行完畢後被呼叫,你可以把它想像成一個「後置處理器」。無論原始方法有無執行,Postfix 一定會被呼叫(除非原始方法拋出未被捕捉的例外)。
- 在原始方法執行後插入邏輯
- 讀取或修改回傳值
- 讀取執行後的 instance 狀態
Harmony Prefix / Postfix 執行流程
Harmony 在攔截原始方法時,三種流程的執行順序如下:
- Prefix → Original Method → Postfix
• 這是最常見的完整流程。
• Prefix 在原始方法執行前呼叫,可以決定是否繼續執行原始方法(回傳 false 可跳過)。
• Original Method 是原本的方法本體。
• Postfix 在原始方法執行後呼叫,可以存取目標方法的回傳值並修改;另外若是 Prefix 回傳 false,則跳過原始方法後執行 Postfix。 - Prefix → Original Method
• 如果沒有定義 Postfix,就只會執行 Prefix 和原始方法。
• Prefix 仍然可以選擇跳過原始方法。 - Original Method → Postfix
• 如果沒有定義 Prefix,就只會執行原始方法和 Postfix。
• Postfix 可以在原始方法執行後補充或修改結果。
| Prefix → Original Method → Postfix | Prefix → Original Method | Original Method → Postfix |
![]() | ![]() | ![]() |
| 註:為了避免圖看起來太亂,Prefix → Original Method → Postfix 關於回傳的部分並未詳細繪製,可以參考右方兩張圖。 | ||
不囉嗦,就拿實際的程式碼來了解用法吧。
基本形式
讓我們從最基本的方式開始,針對靜態方法補丁,Postfix 與 Prefix 不干涉任何原始方法內容,僅僅在執行原始方法前後加上一些程序(比方 Log)。以下是原始方法的內容
public class OriginalClass
{
public static string DisplayMessage(string message)
{
Console.WriteLine("Executing Original Method...");
return $"Original Message : {message}";
}
} 設計一個補丁用的類別,採用 annotation 補丁法:
[HarmonyPatch(typeof(OriginalClass), nameof(OriginalClass.DisplayMessage))]
public static class PatchOriginal
{
/// <summary>
/// Writes a message to the console indicating that the prefix action has occurred.
/// </summary>
public static void Prefix()
{
Console.WriteLine("Prefix: Before the original method.");
}
/// <summary>
/// Performs additional actions after the original method has executed.
/// </summary>
public static void Postfix()
{
Console.WriteLine("Postfix: After the original method.");
}
}這個類別宣告了一個 HarmonyPatch attribute,利用這個 attribute 定義對於哪個類別 – typeof(OriginalClass) 與方法 – nameof(OriginalClass.DisplayMessage) 進行補丁。
類別內部的方法名稱是固定的,分別為 Prefix 與 Postfix,代表著前置作業與後置作業,在這個範例中 Prefix 的回傳值宣告為 void,也就說明的無論如何 original method (也就是 OriginalClass.DisplayMessage) 一定會被執行;由於不需要處理輸入參數,所以 Prefix 方法也沒有定義任何參數。
接著來看主程式:
static void Main(string[] args)
{
var harmony = new Harmony("com.example.sampleApp001");
harmony.PatchAll(Assembly.GetExecutingAssembly());
string result = OriginalClass.DisplayMessage("Hello, Harmony!");
Console.WriteLine(result);
}首先要註冊一個 Harmony 執行個體,要傳入一個唯一的識別碼(ID)"com.example.sampleApp001",用於區分不同的 Harmony 實例。這個 ID 通常以反向域名格式命名,確保全域唯一性;下一行呼叫 PatchAll 方法,掃描這個程式集中所有使用 HarmonyPatch attribute的類別,並根據這些 attribute 自動將補丁應用到原始方法上。
執行結果如下:
Prefix: Before the original method.
Executing Original Method...
Postfix: After the original method.
Original Message : Hello, Harmony!超簡單的對吧,我為了示範方便同時寫了 Prefix 和 Postfix,實際情境中要視情況決定,你可以只有 Prefix 或是只有 Postfix。[範例連結Sample001]
為了避免文章太長,下一篇再繼續。


