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
I know it is not the exact answer to your question, but the usual way to do it is using factories/proxy approach.
First we declare a base type.
public class SimpleClass
{
public virtual 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;
}
}
Then we can declare a derived type (call it proxy).
public class DistributedClass
{
public override DTask<bool> Solve(int n, DEvent<bool> callback)
{
CodeToExecuteBefore();
return base.Slove(n, callback);
}
}
// At runtime
MyClass myInstance;
if (distributed)
myInstance = new DistributedClass();
else
myInstance = new SimpleClass();
The derived type can be also generated at runtime.
public static class Distributeds
{
private static readonly ConcurrentDictionary<Type, Type> pDistributedTypes = new ConcurrentDictionary<Type, Type>();
public Type MakeDistributedType(Type type)
{
Type result;
if (!pDistributedTypes.TryGetValue(type, out result))
{
if (there is at least one method that have [Distributed] attribute)
{
result = create a new dynamic type that inherits the specified type;
}
else
{
result = type;
}
pDistributedTypes[type] = result;
}
return result;
}
public T MakeDistributedInstance<T>()
where T : class
{
Type type = MakeDistributedType(typeof(T));
if (type != null)
{
// Instead of activator you can also register a constructor delegate generated at runtime if performances are important.
return Activator.CreateInstance(type);
}
return null;
}
}
// In your code...
MyClass myclass = Distributeds.MakeDistributedInstance<MyClass>();
myclass.Solve(...);
The only performance loss is during construction of the derived object, the first time is quite slow because it will use a lot of reflection and reflection emit. All other times, it is the cost of a concurrent table lookup and a constructor. As said, you can optimize construction using
ConcurrentDictionary<Type, Func<object>>.
You CAN modify a method's content at runtime. But you're not supposed to, and it's strongly recommended to keep that for test purposes.
Just have a look at:
http://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time
Basically, you can:
Mess with these bytes.
If you just wish to prepend or append some code, then just preprend/append opcodes you want (be careful about leaving stack clean, though)
Here are some tips to "uncompile" existing IL:
Once modified, you IL byte array can be reinjected via InjectionHelper.UpdateILCodes(MethodInfo method, byte[] ilCodes) - see link mentioned above
This is the "unsafe" part... It works well, but this consists in hacking internal CLR mechanisms...
Disclosure: Harmony is a library that was written and is maintained by me, the author of this post.
Harmony 2 is an open source library (MIT license) designed to replace, decorate or modify existing C# methods of any kind during runtime. It main focus is games and plugins written in Mono or .NET. It takes care of multiple changes to the same method - they accumulate instead of overwrite each other.
It creates dynamic replacement methods for every original method and emits code to them that calls custom methods at the start and end. It also allows you to write filters to process the original IL code and custom exception handlers which allows for more detailed manipulation of the original method.
To complete the process, it writes a simple assembler jump into the trampoline of the original method that points to the assembler generated from compiling the dynamic method. This works for 32/64Bit on Windows, macOS and any Linux that Mono supports.
Documentation can be found here.
(Source)
Original Code
public class SomeGameClass
{
private bool isRunning;
private int counter;
private int DoSomething()
{
if (isRunning)
{
counter++;
return counter * 10;
}
}
}
Patching with Harmony annotations
using SomeGame;
using HarmonyLib;
public class MyPatcher
{
// make sure DoPatching() is called at start either by
// the mod loader or by your injector
public static void DoPatching()
{
var harmony = new Harmony("com.example.patch");
harmony.PatchAll();
}
}
[HarmonyPatch(typeof(SomeGameClass))]
[HarmonyPatch("DoSomething")]
class Patch01
{
static FieldRef<SomeGameClass,bool> isRunningRef =
AccessTools.FieldRefAccess<SomeGameClass, bool>("isRunning");
static bool Prefix(SomeGameClass __instance, ref int ___counter)
{
isRunningRef(__instance) = true;
if (___counter > 100)
return false;
___counter = 0;
return true;
}
static void Postfix(ref int __result)
{
__result *= 2;
}
}
Alternatively, manual patching with reflection
using SomeGame;
using HarmonyLib;
public class MyPatcher
{
// make sure DoPatching() is called at start either by
// the mod loader or by your injector
public static void DoPatching()
{
var harmony = new Harmony("com.example.patch");
var mOriginal = typeof(SomeGameClass).GetMethod("DoSomething", BindingFlags.Instance | BindingFlags.NonPublic);
var mPrefix = typeof(MyPatcher).GetMethod("MyPrefix", BindingFlags.Static | BindingFlags.Public);
var mPostfix = typeof(MyPatcher).GetMethod("MyPostfix", BindingFlags.Static | BindingFlags.Public);
// add null checks here
harmony.Patch(mOriginal, new HarmonyMethod(mPrefix), new HarmonyMethod(mPostfix));
}
public static void MyPrefix()
{
// ...
}
public static void MyPostfix()
{
// ...
}
}
Logman's solution, but with an interface for swapping method bodies. Also, a simpler example.
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace DynamicMojo
{
class Program
{
static void Main(string[] args)
{
Animal kitty = new HouseCat();
Animal lion = new Lion();
var meow = typeof(HouseCat).GetMethod("Meow", BindingFlags.Instance | BindingFlags.NonPublic);
var roar = typeof(Lion).GetMethod("Roar", BindingFlags.Instance | BindingFlags.NonPublic);
Console.WriteLine("<==(Normal Run)==>");
kitty.MakeNoise(); //HouseCat: Meow.
lion.MakeNoise(); //Lion: Roar!
Console.WriteLine("<==(Dynamic Mojo!)==>");
DynamicMojo.SwapMethodBodies(meow, roar);
kitty.MakeNoise(); //HouseCat: Roar!
lion.MakeNoise(); //Lion: Meow.
Console.WriteLine("<==(Normality Restored)==>");
DynamicMojo.SwapMethodBodies(meow, roar);
kitty.MakeNoise(); //HouseCat: Meow.
lion.MakeNoise(); //Lion: Roar!
Console.Read();
}
}
public abstract class Animal
{
public void MakeNoise() => Console.WriteLine($"{this.GetType().Name}: {GetSound()}");
protected abstract string GetSound();
}
public sealed class HouseCat : Animal
{
protected override string GetSound() => Meow();
private string Meow() => "Meow.";
}
public sealed class Lion : Animal
{
protected override string GetSound() => Roar();
private string Roar() => "Roar!";
}
public static class DynamicMojo
{
/// <summary>
/// Swaps the function pointers for a and b, effectively swapping the method bodies.
/// </summary>
/// <exception cref="ArgumentException">
/// a and b must have same signature
/// </exception>
/// <param name="a">Method to swap</param>
/// <param name="b">Method to swap</param>
public static void SwapMethodBodies(MethodInfo a, MethodInfo b)
{
if (!HasSameSignature(a, b))
{
throw new ArgumentException("a and b must have have same signature");
}
RuntimeHelpers.PrepareMethod(a.MethodHandle);
RuntimeHelpers.PrepareMethod(b.MethodHandle);
unsafe
{
if (IntPtr.Size == 4)
{
int* inj = (int*)b.MethodHandle.Value.ToPointer() + 2;
int* tar = (int*)a.MethodHandle.Value.ToPointer() + 2;
byte* injInst = (byte*)*inj;
byte* tarInst = (byte*)*tar;
int* injSrc = (int*)(injInst + 1);
int* tarSrc = (int*)(tarInst + 1);
int tmp = *tarSrc;
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
*injSrc = (((int)tarInst + 5) + tmp) - ((int)injInst + 5);
}
else
{
throw new NotImplementedException($"{nameof(SwapMethodBodies)} doesn't yet handle IntPtr size of {IntPtr.Size}");
}
}
}
private static bool HasSameSignature(MethodInfo a, MethodInfo b)
{
bool sameParams = !a.GetParameters().Any(x => !b.GetParameters().Any(y => x == y));
bool sameReturnType = a.ReturnType == b.ReturnType;
return sameParams && sameReturnType;
}
}
}
have a look into Mono.Cecil:
using Mono.Cecil;
using Mono.Cecil.Inject;
public class Patcher
{
public void Patch()
{
// Load the assembly that contains the hook method
AssemblyDefinition hookAssembly = AssemblyLoader.LoadAssembly("MyHookAssembly.dll");
// Load the assembly
AssemblyDefinition targetAssembly = AssemblyLoader.LoadAssembly("TargetAssembly.dll");
// Get the method definition for the injection definition
MethodDefinition myHook = hookAssembly.MainModule.GetType("HookNamespace.MyHookClass").GetMethod("MyHook");
// Get the method definition for the injection target.
// Note that in this example class Bar is in the global namespace (no namespace), which is why we don't specify the namespace.
MethodDefinition foo = targetAssembly.MainModule.GetType("Bar").GetMethod("Foo");
// Create the injector
InjectionDefinition injector = new InjectionDefinition(foo, myHook, InjectFlags.PassInvokingInstance | InjectFlags.passParametersVal);
// Perform the injection with default settings (inject into the beginning before the first instruction)
injector.Inject();
// More injections or saving the target assembly...
}
}
There exists a couple of frameworks that allows you to dynamically change any method at runtime (they use the ICLRProfiling interface mentioned by user152949):
There are also a few frameworks that mocks around with the internals of .NET, these are likely more fragile, and probably can't change inlined code, but on the other hand they are fully self-contained and does not require you to use a custom launcher.