Skip to content

Magic Parameters ​

Harmony patch methods can declare special parameters (prefixed with double underscore) that are automatically injected by Harmony at call time. Mastering them is fundamental to writing patches.

Parameter Overview ​

ParameterWhereDescription
__instanceAny patchThe current object instance of the target method (for instance methods)
__resultPrefix / Postfix / FinalizerReturn value
__statePrefix / Postfix / FinalizerCross-patch value passing (Prefix→Postfix)
__argsAny patchAll parameters of the target method (object[])
__originalMethodAny patchThe original MethodBase (the method before patching)
___fieldNameAny patchRead a field of the target class (triple underscore)

__instance: Current Instance ​

Available when the target method is an instance method. The type can be the target class or any of its base classes:

csharp
public static void Prefix(Player __instance)
{
    var speed = __instance.speed;
}
  • Using object as the type is also valid (cast when needed)
  • For static methods / constructors, this is null

__result: Return Value ​

  • Prefix: initially the default value for the type (0, null, false)
  • Postfix / Finalizer: the actual return value after the target method executes
  • To modify the return value, you must use ref:
csharp
public static void Postfix(ref int __result)
{
    __result = Math.Abs(__result);
}

__state: Cross-Patch Value Passing ​

Store a value in Prefix (must use ref), read it in Postfix / Finalizer:

csharp
public static void Prefix(ref float __state)
{
    __state = Time.deltaTime;   // Remember the time before method execution
}

public static void Postfix(float __state)
{
    // __state is the value from before execution
}
  • The type must be consistent between Prefix and Postfix
  • If only Postfix exists, __state is the type's default value

__args: All Parameters ​

Get all input parameters of the target method as object[] (read-only view):

csharp
public static void Prefix(object[] __args)
{
    foreach (var a in __args) MyMod.Logger.Log(a?.ToString() ?? "null");
}

To modify parameters, the "parameter name + ref" approach is clearer (see Prefix Patch).

__originalMethod: Original Method ​

When manually patching or needing to call the original method, you can get the original MethodBase:

csharp
public static void Prefix(MethodBase __originalMethod)
{
    MyMod.Logger.Log($"Calling {__originalMethod.Name}");
}

___fieldName: Reading Private Fields ​

Triple underscore + field name lets you read private fields of the target class:

csharp
// Read the private field _score of the Scoring class
public static void Postfix(Scoring __instance)
{
    var score = __instance._score;    // Public/internal field
    var raw = __instance.___rawScore; // Private field: triple underscore
}

WARNING

The field name must exactly match the decompiled result (case-sensitive). Reading fields with ___ is essentially reflection — frequent access has performance overhead, use sparingly in hot paths.

Combining ​

Magic parameters can be freely combined:

csharp
public static void Prefix(Player __instance, ref float __state, object[] __args)
{
    // ...
}

What You Learned ​

  • The purpose of the six magic parameters
  • How to modify __result (with ref)
  • Cross-patch value passing with __state
  • Reading private fields with ___

Next Step ​

Dive deeper into the various syntaxes of [HarmonyPatch] → HarmonyPatch Details

An organization that researches and expands the functions of ADOFAI