Skip to content

Instantly share code, notes, and snippets.

@pardeike
Created April 25, 2020 11:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pardeike/45196a8b8ef331f38b14e1a7e5ee1782 to your computer and use it in GitHub Desktop.
Save pardeike/45196a8b8ef331f38b14e1a7e5ee1782 to your computer and use it in GitHub Desktop.
Calling a base method from a patch is hard
// run this from LINQPad
// don't forget to add the dependencies to Harmony
void Main()
{
var harmony = new Harmony("test");
harmony.PatchAll();
var bar = new Bar();
Prefix(bar);
// will print
// Bar.Test(1)
// Bar.Test(2)
// Bar.Test(3)
// Bar.Test(4)
// Bar.Test(5)
// Foo.Test(6)
}
[HarmonyPatch(typeof(Foo), "Test")]
class Patch
{
[HarmonyReversePatch]
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Test(Foo instance, string s)
{
Console.WriteLine($"Patch.Test({instance}, {s})");
}
}
static MethodInfo mTest = typeof(Foo).GetMethod("Test");
static FastInvokeHandler Test = MethodInvoker.GetHandler(mTest, true);
delegate void TestDelegate(Foo instance, string s);
static TestDelegate dTest = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), mTest);
public void Prefix(Bar bar)
{
// normal call
bar.Test("1");
// casting does not work
((Foo)bar).Test("2");
// simple invoke does not work
mTest.Invoke(bar, new[] { "3" });
// FastInvokeHandler does not work
Test(bar, new[] { "4" });
// delegate does not work
dTest(bar, "5");
// Reverse patch works
Patch.Test(bar, "6");
}
public class Foo
{
public virtual void Test(string s)
{
Console.WriteLine($"Foo.Test({s})");
}
}
public class Bar : Foo
{
public override void Test(string s)
{
Console.WriteLine($"Bar.Test({s})");
}
}
@Cattlesquat
Copy link

Would love to see an example where the base method returns a value instead of just being void -- haven't figured out how to get that to work right.

@pardeike
Copy link
Author

In line 26, you just define your dummy to be the same as the original. If your original has a return value then your dummy would too.

@MADH95
Copy link

MADH95 commented Nov 6, 2021

Having a similar issue, but the base class thing i'm trying to access is a protected property. Not sure how to deal with that.

@pardeike
Copy link
Author

pardeike commented Nov 6, 2021

Properties are just methods. You adapt the annotations of the reverse patch according to the documentation to specify a property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment