C# 中的猴子修补

发布于 2024-10-09 10:48:04 字数 119 浏览 1 评论 0原文

是否可以在运行时扩展或修改 C# 类的代码?

我的问题具体围绕 Monkey Patching / Duck Punching 或元对象编程 (MOP),就像 Groovy、Ruby 等脚本语言中发生的那样。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

与他有关 2024-10-16 10:48:04

对于那些今天仍然在这个问题上绊倒的人来说,确实有一个名为 Harmony 的当今库,它相对-直接在运行时启用此类猴子修补。它的重点是视频游戏模组(特别是使用 Unity 构建的游戏),但并没有太多阻止人们在该用例之外使用它。

从他们的 introduction 复制示例,如果您有这样的现有类:

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

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

那么 Harmony 可以像这样修补它:

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;
    }
}

在这里,我们有一个“前缀”补丁,它会在原始方法运行之前插入,允许我们在方法内设置变量,在方法的类上设置字段,甚至完全跳过原始方法。我们还有一个“后缀”补丁,它会在原始方法运行后插入,并且可以操作返回值等内容。

显然,这并不像您可以在 Ruby 中进行的猴子修补那么好,并且有 许多警告可能会妨碍它的实用性,具体取决于您的用例,但在您确实需要改变方法的情况下,Harmony 是一种经过验证的方法。

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.

离线来电— 2024-10-16 10:48:04

是否可以在运行时扩展或修改 C# 类的代码?

不,在 .NET 中不可能执行此操作。您可以编写派生类并重写方法(如果它们是虚拟的),但您不能修改现有类。试想一下,如果您所要求的事情是可能的:您可以修改某些现有系统类(如 System.String)的行为。

您还可以查看扩展方法,以向现有的班级。

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.

谜兔 2024-10-16 10:48:04

您可以添加功能,但无法更改或删除功能。

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

救赎№ 2024-10-16 10:48:04

您可以通过添加额外的方法来扩展类,但不能覆盖它们,因为添加的方法的优先级始终低于现有方法。

有关详细信息,请参阅 C# 编程指南中的扩展方法

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文