Skip to content

Instantly share code, notes, and snippets.

@vermorel
Last active September 7, 2023 06:06
Show Gist options
  • Save vermorel/94d5ca87bb342190160ce8452a1c04d4 to your computer and use it in GitHub Desktop.
Save vermorel/94d5ca87bb342190160ce8452a1c04d4 to your computer and use it in GitHub Desktop.
C# utility method that converts a Delegate into a MethodInfo
using System.Reflection;
using System.Reflection.Emit;
public static class DelegateHelper
{
/// <summary>
/// Compile the 'Delegate' to a static method.
/// </summary>
public static MethodInfo CompileToMethod(Delegate del)
{
var methodInfo = del.Method;
var type = del.GetType();
AssemblyName assemblyName = new AssemblyName(type.Name + "Wrap");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
var tb = moduleBuilder.DefineType(type.Name + "Wrap", TypeAttributes.Public | TypeAttributes.Class);
var instanceField = tb.DefineField("Instance", typeof(Delegate), FieldAttributes.Private | FieldAttributes.Static);
// first parameter is a closure, it should be ignored
var parameters = methodInfo.GetParameters().Skip(1).ToArray();
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
var newMethod = tb.DefineMethod("DynamicInvoke",
MethodAttributes.Public | MethodAttributes.Static,
methodInfo.ReturnType, parameterTypes);
var il = newMethod.GetILGenerator();
var argsArray = il.DeclareLocal(typeof(object[]));
il.Emit(OpCodes.Ldc_I4, parameterTypes.Length);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc, argsArray);
for (int i = 0; i < parameterTypes.Length; i++)
{
il.Emit(OpCodes.Ldloc, argsArray);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldarg, i);
if (parameterTypes[i].IsValueType)
{
il.Emit(OpCodes.Box, parameterTypes[i]);
}
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Ldsfld, instanceField);
il.Emit(OpCodes.Ldloc, argsArray);
il.Emit(OpCodes.Callvirt, type.GetMethod("DynamicInvoke", new[] { typeof(object[]) }));
if (methodInfo.ReturnType != typeof(void))
{
if (methodInfo.ReturnType.IsValueType)
{
il.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);
}
}
else
{
il.Emit(OpCodes.Pop);
}
il.Emit(OpCodes.Ret);
var newType = tb.CreateType();
newType.GetField("Instance", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, del);
return newType.GetMethod("DynamicInvoke");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment