是否可以在运行时扩展或修改C#类的代码?
我的问题特别围绕Monkey Patching / Duck Punching或元对象编程(MOP),因为它发生在Groovy,Ruby等脚本语言中。
答案 0 :(得分:7)
是否可以在运行时扩展或修改C#类的代码?
不可以在.NET中执行此操作。您可以编写派生类和覆盖方法(如果它们是虚拟的)但您不能修改现有类。试想一下,如果你问的是可能的:你可以修改一些现有系统类的行为,比如System.String。
您还可以查看Extension methods以向现有类添加功能。
答案 1 :(得分:3)
您可以添加功能,但无法更改或删除功能。
答案 2 :(得分:2)
您可以通过添加额外的方法来扩展类,但不能覆盖它们,因为添加的方法的优先级始终低于现有方法。
有关详细信息,请参阅C#编程指南中的Extension Methods。
答案 3 :(得分:1)
对于那些在今天仍然在这个问题上磕磕绊绊的人来说,确实有一个名为 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,并且有 a lot of caveats 可能会影响其实用性,具体取决于您的用例,但在您确实需要更改方法的情况下,Harmony 是一种经过充分验证的方法。