为了账号安全,请及时绑定邮箱和手机立即绑定

动态替换C#方法的内容?

动态替换C#方法的内容?

C#
慕侠2389804 2019-08-24 18:10:33
动态替换C#方法的内容?我想要做的是改变C#方法在调用时的执行方式,这样我就可以编写如下内容:[Distributed]public DTask<bool> Solve(int n, DEvent<bool> callback){     for (int m = 2; m < n - 1; m += 1)         if (m % n == 0)             return false;     return true;}在运行时,我需要能够分析具有Distributed属性(我已经可以做)的方法,然后在函数体执行之前和函数返回之后插入代码。更重要的是,我需要能够在不修改调用Solve的代码的情况下或在函数的开头修改代码(在编译时;在运行时这样做是目标)。目前我尝试了这段代码(假设t是Solve存储的类型,m是Solve的MethodInfo):private void WrapMethod(Type t, MethodInfo m){     // Generate ILasm for delegate.     byte[] il = typeof(Dpm).GetMethod("ReplacedSolve").GetMethodBody().GetILAsByteArray();     // Pin the bytes in the garbage collection.     GCHandle h = GCHandle.Alloc((object)il, GCHandleType.Pinned);     IntPtr addr = h.AddrOfPinnedObject();     int size = il.Length;     // Swap the method.     MethodRental.SwapMethodBody(t, m.MetadataToken, addr, size, MethodRental.JitImmediate);}public DTask<bool> ReplacedSolve(int n, DEvent<bool> callback){     Console.WriteLine("This was executed instead!");     return true;}但是,MethodRental.SwapMethodBody仅适用于动态模块; 不是那些已经编译并存储在程序集中的。所以我正在寻找一种方法来有效地对已经存储在已加载和执行的程序集中的方法执行SwapMethodBody 。注意,如果我必须将方法完全复制到动态模块中,这不是问题,但在这种情况下,我需要找到一种方法来复制IL并更新所有对Solve()的调用,以便它们会指向新副本。
查看完整描述

3 回答

?
MM们

TA贡献1886条经验 获得超2个赞

基于这个问题和另一个问题的答案,我提出了这个整理版本:

public static unsafe MethodReplacementState Replace(this MethodInfo methodToReplace, MethodInfo methodToInject)
        {//#if DEBUG
            RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
            RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);//#endif
            MethodReplacementState state;

            IntPtr tar = methodToReplace.MethodHandle.Value;
            if (!methodToReplace.IsVirtual)
                tar += 8;
            else
            {
                var index = (int)(((*(long*)tar) >> 32) & 0xFF);
                var classStart = *(IntPtr*)(methodToReplace.DeclaringType.TypeHandle.Value + (IntPtr.Size == 4 ? 40 : 64));
                tar = classStart + IntPtr.Size * index;
            }
            var inj = methodToInject.MethodHandle.Value + 8;#if DEBUG
            tar = *(IntPtr*)tar + 1;
            inj = *(IntPtr*)inj + 1;
            state.Location = tar;
            state.OriginalValue = new IntPtr(*(int*)tar);

            *(int*)tar = *(int*)inj + (int)(long)inj - (int)(long)tar;
            return state;#else
            state.Location = tar;
            state.OriginalValue = *(IntPtr*)tar;
            * (IntPtr*)tar = *(IntPtr*)inj;
            return state;#endif
        }
    }

    public struct MethodReplacementState : IDisposable
    {
        internal IntPtr Location;
        internal IntPtr OriginalValue;
        public void Dispose()
        {
            this.Restore();
        }

        public unsafe void Restore()
        {#if DEBUG
            *(int*)Location = (int)OriginalValue;#else
            *(IntPtr*)Location = OriginalValue;#endif
        }
    }


查看完整回答
反对 回复 2019-08-24
  • 3 回答
  • 0 关注
  • 880 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信