Last active
September 7, 2023 06:06
-
-
Save vermorel/94d5ca87bb342190160ce8452a1c04d4 to your computer and use it in GitHub Desktop.
C# utility method that converts a Delegate into a MethodInfo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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