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

动态替换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()的调用,以便它们会指向新副本。



慕侠2389804
浏览 890回答 3
3回答

MM们

基于这个问题和另一个问题的答案,我提出了这个整理版本:public&nbsp;static&nbsp;unsafe&nbsp;MethodReplacementState&nbsp;Replace(this&nbsp;MethodInfo&nbsp;methodToReplace,&nbsp;MethodInfo&nbsp;methodToInject) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{//#if&nbsp;DEBUG &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);//#endif &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodReplacementState&nbsp;state; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IntPtr&nbsp;tar&nbsp;=&nbsp;methodToReplace.MethodHandle.Value; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!methodToReplace.IsVirtual) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tar&nbsp;+=&nbsp;8; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;index&nbsp;=&nbsp;(int)(((*(long*)tar)&nbsp;>>&nbsp;32)&nbsp;&&nbsp;0xFF); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;classStart&nbsp;=&nbsp;*(IntPtr*)(methodToReplace.DeclaringType.TypeHandle.Value&nbsp;+&nbsp;(IntPtr.Size&nbsp;==&nbsp;4&nbsp;?&nbsp;40&nbsp;:&nbsp;64)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tar&nbsp;=&nbsp;classStart&nbsp;+&nbsp;IntPtr.Size&nbsp;*&nbsp;index; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;inj&nbsp;=&nbsp;methodToInject.MethodHandle.Value&nbsp;+&nbsp;8;#if&nbsp;DEBUG &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tar&nbsp;=&nbsp;*(IntPtr*)tar&nbsp;+&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inj&nbsp;=&nbsp;*(IntPtr*)inj&nbsp;+&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.Location&nbsp;=&nbsp;tar; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.OriginalValue&nbsp;=&nbsp;new&nbsp;IntPtr(*(int*)tar); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*(int*)tar&nbsp;=&nbsp;*(int*)inj&nbsp;+&nbsp;(int)(long)inj&nbsp;-&nbsp;(int)(long)tar; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;state;#else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.Location&nbsp;=&nbsp;tar; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.OriginalValue&nbsp;=&nbsp;*(IntPtr*)tar; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;(IntPtr*)tar&nbsp;=&nbsp;*(IntPtr*)inj; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;state;#endif &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;struct&nbsp;MethodReplacementState&nbsp;:&nbsp;IDisposable &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;internal&nbsp;IntPtr&nbsp;Location; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;internal&nbsp;IntPtr&nbsp;OriginalValue; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;Dispose() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.Restore(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;unsafe&nbsp;void&nbsp;Restore() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{#if&nbsp;DEBUG &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*(int*)Location&nbsp;=&nbsp;(int)OriginalValue;#else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*(IntPtr*)Location&nbsp;=&nbsp;OriginalValue;#endif &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}
打开App,查看更多内容
随时随地看视频慕课网APP