1 /* https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method
2 For .NET 4 and above
3
4 "C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe" /unsafe+ /out:replacemethod.exe replacemethod.cs && start "replacemethod.exe" replacemethod.exe
5 PrintInfo: Version x64 Release
6
7 1. Replace Instance Method Class1.Demo()
8 Demo
9 Replace result: True
10 Foo
11
12 2. Replace Instance Overload of Method Class1.Demo(10)
13 Demo: 10
14 Replace result: True
15 Foo: 10
16
17 3. Replace Static Method Class1.DemoStatic()
18 DemoStatic
19 Replace result: True
20 FooStatic
21
22 Press any key to EXIT...
23 */
24
25 using System;
26 using System.Reflection;
27 using System.Runtime.CompilerServices;
28
29 class Program {
30 public static void Main(params string[] args){
31 PrintInfo();
32 Console.WriteLine();
33
34 Test();
35
36 Console.Write("\nPress any key to EXIT...");
37 Console.ReadKey(true);
38 }
39
40 public static void PrintInfo() {
41 Console.Write("PrintInfo: ");
42 if (IntPtr.Size == 4) {
43 #if DEBUG
44 Console.WriteLine("Version x86 Debug");
45 #else
46 Console.WriteLine("Version x86 Release");
47 #endif
48 } else {
49 #if DEBUG
50 Console.WriteLine("Version x64 Debug");
51 #else
52 Console.WriteLine("Version x64 Release");
53 #endif
54 }
55 }
56
57 public static void Test() {
58 Console.WriteLine("1. Replace Instance Method Class1.Demo()");
59 var o = new Class1();
60 o.Demo();
61 var r = CSharpUtils.ReplaceMethod(typeof(Class1), "Demo", typeof(Program), "Foo");
62 Console.WriteLine("Replace result: {0}", r);
63 o.Demo();
64
65 Console.WriteLine();
66
67 Console.WriteLine("2. Replace Instance Overload of Method Class1.Demo(10)");
68 o.Demo(10);
69 r = CSharpUtils.ReplaceMethod(typeof(Class1), "Demo", typeof(Program), "Foo", types:new Type[]{ typeof(int) });
70 Console.WriteLine("Replace result: {0}" ,r);
71 o.Demo(10);
72
73 Console.WriteLine();
74
75 Console.WriteLine("3. Replace Static Method Class1.DemoStatic()");
76 Class1.DemoStatic();
77 r = CSharpUtils.ReplaceMethod(typeof(Class1), "DemoStatic", typeof(Program), "FooStatic", BindingFlags.Static|BindingFlags.NonPublic|BindingFlags.Public);
78 Console.WriteLine("Replace result: {0}" ,r);
79 Class1.DemoStatic();
80 }
81
82 private void Foo() {
83 Console.WriteLine("Foo");
84 }
85
86 private void Foo(int d) {
87 Console.WriteLine("Foo: {0}", d);
88 }
89
90 private static void FooStatic() {
91 Console.WriteLine("FooStatic");
92 }
93 }
94
95
96 class Class1 {
97 public void Demo() {
98 Console.WriteLine("Demo");
99 }
100
101 public void Demo(int d) {
102 Console.WriteLine("Demo: {0}", d);
103 }
104
105 public static void DemoStatic() {
106 Console.WriteLine("DemoStatic");
107 }
108 }
109
110
111 public static class CSharpUtils {
112 public static bool ReplaceMethod(Type targetType, string targetMethod, Type injectType, string injectMethod, BindingFlags bindingAttr = BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public, Binder binder = null, CallingConventions callConvention = CallingConventions.Any, Type[] types = null, ParameterModifier[] modifiers = null) {
113 if (types == null) {
114 types = Type.EmptyTypes;
115 }
116 MethodInfo tarMethod = targetType.GetMethod(targetMethod, bindingAttr, binder, callConvention, types, modifiers);
117 MethodInfo injMethod = injectType.GetMethod(injectMethod, bindingAttr, binder, callConvention, types, modifiers);
118 if (tarMethod == null || injMethod == null) {
119 return false;
120 }
121 RuntimeHelpers.PrepareMethod(tarMethod.MethodHandle);
122 RuntimeHelpers.PrepareMethod(injMethod.MethodHandle);
123 unsafe {
124 if (IntPtr.Size == 4) {
125 int* tar = (int*)tarMethod.MethodHandle.Value.ToPointer() + 2;
126 int* inj = (int*)injMethod.MethodHandle.Value.ToPointer() + 2;
127 *tar = *inj;
128 } else {
129 long* tar = (long*)tarMethod.MethodHandle.Value.ToPointer() + 1;
130 long* inj = (long*)injMethod.MethodHandle.Value.ToPointer() + 1;
131 *tar = *inj;
132 }
133 }
134 return true;
135 }
136 }