怎样让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 originalCall, Expression targetCall);
}

从如下所示的输出可以看出:虽然源程序我们调用的是Add方法,实际上最终的调用被转移到Add2方法上。

我们知道通过C#编写的.NET程序在编译后会转化成IL Code,在运行时以及时编译的方式转化成机器指令。如果想“篡改”某个方法的实现,要么在JIT之前改变IL代码,要么直接修改最终的机器指令。Override方法采用的是第二种解决方案,如下所示的该方法的实现,基本的思路就是将将原方法的机器指令修改为JUMP(对应x86二进制为0xE9)指令实现向目标方法的跳转。

public static void Override(Expression originalCall, Expression 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在设计上的一个问题,希望在以后的版本中能够解决这个问题。

作者:蒋金楠

出处:https://www.cnblogs.com/artech/p/11354583.html。

本文版权归作者和博客园共有。


相关:

浙江宁波70年发展回望:从商埠小城到国际港口名城  中新网宁波10月5日电(记者 林波)1949年,新中国成立初期,作为一个商埠小城,浙江宁波城市建成区面积狭小,仅18.3平方公里,地区生产总值仅为2.2亿元(人民币,下同)。经过70年的建设,宁波建成区面积达到345...

脱贫攻坚交通先行 贵州全力解决“最后一公里”  中新网10月5日电 题:脱贫攻坚交通先行 贵州全力解决“最后一公里”   记者 蒲文思   路通民心畅,道顺百业兴。近年来,随着县县通高速公路、高铁时代到来、航空客运崛起,水路航运兴起而形成的立体..

200件军事收藏讲述国防故事 退役老兵再圆“强国梦”  中新网嘉兴10月5日电(见习记者 刘方齐)坦克、轰炸机、装甲车、高射炮、军用运输车……近8000平方米的浙江嘉兴国防科普文化馆内,让人梦寐以求的许多国防“大件”都触手可及。   将这200多件军事藏品集齐的..