Dynamically replace the contents of a C# method?

后端 未结 10 2284
面向向阳花
面向向阳花 2020-11-22 16:09

What I want to do is change how a C# method executes when it is called, so that I can write something like this:

[Distributed]
public DTask Solve         


        
10条回答
  •  有刺的猬
    2020-11-22 16:36

    Based on the answer to this question and another, ive came up with this tidied up version:

    // Note: This method replaces methodToReplace with methodToInject
    // Note: methodToInject will still remain pointing to the same location
    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
            }
        }
    

提交回复
热议问题