C#中强制重写不可修改非虚方法?游戏DLC开发技术求助
非虚方法的子类逻辑替换方案(C#游戏DLC场景)
方案一:用Harmony进行方法钩子(游戏开发常用)
这是Unity等游戏DLC开发里最通用的解决方案,无需修改原生代码:
- 导入Harmony库(可通过NuGet或Unity Package Manager安装)
- 编写钩子代码拦截
Player.RedBooster方法,按需替换调用逻辑:
using HarmonyLib; [HarmonyPatch(typeof(Player), nameof(Player.RedBooster))] public static class PlayerRedBoosterPatch { // 拦截原方法,自定义执行逻辑 static bool Prefix(Booster booster) { if (booster is PerpetualBooster perpetualBooster) { // 调用子类自定义的walk逻辑 perpetualBooster.CustomWalk(); return false; // 跳过原方法的执行 } return true; // 非子类实例,执行原方法逻辑 } }
- 在DLC初始化时启动Harmony:
var harmony = new Harmony("com.yourdlc.namespace"); harmony.PatchAll();
方案二:反射修改IL实现(无第三方库)
如果不想依赖第三方库,可手动通过反射修改Player.RedBooster的IL代码,实现类型判断与逻辑分支:
using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; // 获取原生方法的MethodInfo var redBoosterMethod = typeof(Player).GetMethod(nameof(Player.RedBooster), BindingFlags.Public | BindingFlags.Instance); // 创建动态方法替换原逻辑 var dynamicMethod = new DynamicMethod( "RedBoosterHook", null, new Type[] { typeof(Player), typeof(Booster) }, typeof(Player).Module ); var il = dynamicMethod.GetILGenerator(); // 判断传入的Booster是否为PerpetualBooster实例 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Isinst, typeof(PerpetualBooster)); var executeOriginal = il.DefineLabel(); il.Emit(OpCodes.Brfalse_S, executeOriginal); // 是子类实例,调用自定义walk方法 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Castclass, typeof(PerpetualBooster)); il.Emit(OpCodes.Callvirt, typeof(PerpetualBooster).GetMethod(nameof(PerpetualBooster.CustomWalk), BindingFlags.Public | BindingFlags.Instance)); il.Emit(OpCodes.Ret); // 非子类实例,执行原方法逻辑 il.MarkLabel(executeOriginal); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, redBoosterMethod); il.Emit(OpCodes.Ret); // 替换原方法的实现指针 var methodPtr = redBoosterMethod.MethodHandle.GetFunctionPointer(); Marshal.WriteIntPtr(methodPtr, dynamicMethod.MethodHandle.GetFunctionPointer());
注意:该方案需要掌握基础IL知识,且不同.NET版本可能存在兼容性差异,需在目标游戏环境中充分测试。
方案三:适配器包装(仅适用于可控实例场景)
如果你的DLC可以控制传入Player.RedBooster的Booster实例,可通过适配器包装子类逻辑:
public class PerpetualBoosterAdapter : Booster { private readonly PerpetualBooster _target; public PerpetualBoosterAdapter(PerpetualBooster target) { _target = target; } // 结合方案二的IL修改,让Player调用适配器时触发子类逻辑 }
此方案局限性较大,仅适用于你能完全掌控Booster实例创建与传递的场景。
内容的提问来源于stack exchange,提问作者Gloups
相关产品推荐
相关产品推荐

