C# 中的猴子修补

问题描述 投票:0回答:5

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

我的问题特别围绕 Monkey Patching / Duck Punching 或元对象编程 (MOP),因为它发生在 Groovy、Ruby 等脚本语言中。

dynamic c#-4.0 metaprogramming
5个回答
11
投票

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

复制他们的简介中的示例,如果您有这样的现有课程:

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 是一种经过验证的方法。


8
投票

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

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

您还可以查看扩展方法以向现有类添加功能。


4
投票

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


4
投票

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

有关更多信息,请查看 C# 编程指南中的扩展方法


0
投票

我知道已经是 13 年后的事了,但我在 C# 中提出了功能请求 https://github.com/dotnet/csharplang/discussions/8017 如果有人感兴趣请投票:)

© www.soinside.com 2019 - 2024. All rights reserved.