开发者

Monkey Patching in C#

开发者 https://www.devze.com 2023-02-01 21:00 出处:网络
Is it possible to extend or modify the code of a C# class at runtime? My question specifically revolves开发者_如何学运维 around Monkey Patching / Duck Punching or Meta Object Programming (MOP), as it

Is it possible to extend or modify the code of a C# class at runtime?

My question specifically revolves开发者_如何学运维 around Monkey Patching / Duck Punching or Meta Object Programming (MOP), as it happens in scripting languages such as Groovy, Ruby etc.


For those still stumbling on this question in the present day, there is indeed a present-day library called Harmony that relatively-straightforwardly enables such monkey-patching at runtime. Its focus is on video game modding (particularly games built with Unity), but there ain't much stopping folks from using it outside of that use case.

Copying the example from their introduction, if you have an existing class like so:

public class SomeGameClass
{
    public bool isRunning;
    public int counter;

    private int DoSomething()
    {
        if (isRunning)
        {
            counter++;
        }
        return counter * 10;
    }
}

Then Harmony can patch it like so:

using HarmonyLib;
using Intro_SomeGame;

public class MyPatcher
{
    // make sure DoPatching() is called at start either by
    // the mod loader or by your injector

    public static void DoPatching()
    {
        var harmony = new Harmony("com.example.patch");
        harmony.PatchAll();
    }
}

[HarmonyPatch(typeof(SomeGameClass))]
[HarmonyPatch("DoSomething")]
class Patch01
{
    static AccessTools.FieldRef<SomeGameClass, bool> isRunningRef =
        AccessTools.FieldRefAccess<SomeGameClass, bool>("isRunning");

    static bool Prefix(SomeGameClass __instance, ref int ___counter)
    {
        isRunningRef(__instance) = true;
        if (___counter > 100)
            return false;
        ___counter = 0;
        return true;
    }

    static void Postfix(ref int __result)
    {
        __result *= 2;
    }
}

Here, we have a "prefix" patch which gets inserted before the original method runs, allowing us to set variables within the method, set fields on the method's class, or even skip the original method entirely. We also have a "postfix" patch which gets inserted after the original method runs, and can manipulate things like the return value.

Obviously this ain't quite as nice as the sorts of monkey-patching you can do in e.g. Ruby, and there are a lot of caveats that might hinder its usefulness depending on your use case, but in those situations where you really do need to alter methods, Harmony's a pretty proven approach to doing so.


Is it possible to extend or modify the code of a C# class at run-time?

No it is not possible to do this in .NET. You could write derived classes and override methods (if they are virtual) but you cannot modify an existing class. Just imagine if what you were asking was possible: you could modify the behavior of some existing system classes like System.String.

You may also take a look at Extension methods to add functionality to an existing class.


You can add functionality, but you cannot change or remove functionality.


You can extend classes by adding extra methods, but you cannot override them because added methods have always lower priority than existing ones.

For more info, check Extension Methods in C# Programming Guide.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号