猴子修补C#

hum*_*der 11 metaprogramming dynamic c#-4.0

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

我的问题专门针对Monkey Patching/Duck Punching或元对象编程(MOP),因为它发生在Groovy,Ruby等脚本语言中.

Yel*_*ple 11

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

如果您有一个现有的类,则复制其简介中的示例:

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

    private int DoSomething()
    {
        if (isRunning)
        {
            counter++;
        }
        return counter * 10;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


Dar*_*rov 7

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

不,不可能在.NET中这样做.您可以编写派生类和覆盖方法(如果它们是虚拟的)但您无法修改现有类.试想一下,如果你问的是可能的:你可以修改一些现有系统类的行为,比如System.String.

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

  • "想象一下会发生什么" - 不需要想象.Python允许这样做,虽然它总是一个后门,没有人在必要时真的很开心,但它是解决现实世界问题的极其强大的工具.不应该允许某些东西因为有可能被滥用而无法设计语言的想法. (5认同)
  • @humblecoder,然后看一下扩展方法. (2认同)
  • Monkey 补丁允许您模拟云应用程序和资源等服务,然后您可以对代码运行有意义的单元测试,而无需向生产代码添加特殊情况。而且,这只是一个例子,说明猴子补丁是多么强大并且是一件好事。查看模拟大量 AWS 服务的 `moto` Python 包,这样您就可以测试可交付的代码,而不会因单元测试的花招和杂乱而污染它。 (2认同)
  • @GlennMaynard如果您希望将一种语言用于由数十个不同的人维护的长期代码,而这些人不知道猴子补丁引入的所有怪癖,那么这正是您设计语言的方式 (2认同)