怎样让1+1=3?
如下所示的是一个.NET程序。我们在这段程序中定义了一个作整数加法运算的Add方法,但是我希望将针对这个方法的调用转移到另一个Add2方法上,为此我定义了一个Override方法。
class Program { static void Main() { Override(() => Add(default, default), () => Add2(default, default)); Console.WriteLine($"Add(1, 1) == {Add(1, 1)}"); Console.ReadLine(); } public static int Add(int x, int y) => x + y; public static int Add2(int x, int y) => x + y + 1; public static void Override(Expression<Action> originalCall, Expression<Action> targetCall); }
从如下所示的输出可以看出:虽然源程序我们调用的是Add方法,实际上最终的调用被转移到Add2方法上。
我们知道通过C#编写的.NET程序在编译后会转化成IL Code,在运行时以及时编译的方式转化成机器指令。如果想“篡改”某个方法的实现,要么在JIT之前改变IL代码,要么直接修改最终的机器指令。Override方法采用的是第二种解决方案,如下所示的该方法的实现,基本的思路就是将将原方法的机器指令修改为JUMP(对应x86二进制为0xE9)指令实现向目标方法的跳转。
public static void Override(Expression<Action> originalCall, Expression<Action> targetCall) { var originalMethod = ((MethodCallExpression)originalCall.Body).Method; var targetMethod = ((MethodCallExpression)targetCall.Body).Method; RuntimeHelpers.PrepareMethod(originalMethod.MethodHandle); RuntimeHelpers.PrepareMethod(targetMethod.MethodHandle); var sourceAddress = originalMethod.MethodHandle.GetFunctionPointer(); var targetAddress = (long)targetMethod.MethodHandle.GetFunctionPointer(); int offset = (int)(targetAddress - (long)sourceAddress - 4 - 1); byte[] instruction = { 0xE9, // JUMP (byte)(offset & 0xFF), (byte)((offset >> 8) & 0xFF), (byte)((offset >> 16) & 0xFF), (byte)((offset >> 24) & 0xFF) }; Marshal.Copy(instruction, 0, sourceAddress, instruction.Length); }
这个方式有时候会很有用,我最近应用的场景是希望篡改.NET Core应用中针对IHostEnvironment的如下三个扩展方法的实现,因为我们的部署环境并没有按照默认的命名约定(Development、Staging和Production)这样导致了这三个方法返回错误的结果。但是IsDevelopment方法的返回结果在.NET Core服务承载系统中很重要,所以不得不篡改它的实现逻辑。
public static class HostEnvironmentEnvExtensions { public static bool IsDevelopment(this IHostEnvironment hostEnvironment) =>hostEnvironment.IsEnvironment(Environments.Development); public static bool IsProduction(this IHostEnvironment hostEnvironment) =>hostEnvironment.IsEnvironment(Environments.Production); public static bool IsStaging(this IHostEnvironment hostEnvironment) =>hostEnvironment.IsEnvironment(Environments.Staging); } public static class Environments { public static readonly string Development = "Development"; public static readonly string Production = "Production"; public static readonly string Staging = "Staging"; }
从某种意义上讲,这也体现了.NET Core Hosting System在设计上的一个问题,希望在以后的版本中能够解决这个问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
2014-08-14 《ASP.NET MVC 5框架揭秘》样章发布
2012-08-14 了解ASP.NET MVC几种ActionResult的本质:FileResult
2010-08-14 年纪大了,却越来越激愤了