Creating delegate types via Reflection.Emit
There's been a few questions on various newsgroups asking for the code sequence for generating a delegate type at runtime. I've cooked up a bit of code which illustrates the various attribute parameters that you need to pass to the Reflection.Emit builders.
The example uses Reflection to crack open the method signature for “MyClass.MyConsoleWriteLineMethod(string output)” and then constructs and bakes a delegate type for that particular signature. One thing to recognise is the typeof(System.IntPtr) passed to the ConstructorBuilder, this will give you that “native int“ IL method sig you're after. The code follows, along with the ILDASM output:
ReflectionEmitDelegate.cs
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace DelegateReflectionEmit
{
// Random class that has the method signature I want
public class MyClass
{
public void MyConsoleWriteLineMethod(string output)
{
Console.WriteLine(output);
}
}
class REDelegate
{
[STAThread]
static void Main(string[] args)
{
AssemblyName assembly;
AssemblyBuilder assemblyBuilder;
ModuleBuilder modbuilder;
TypeBuilder typeBuilder;
MethodBuilder methodBuilder;
assembly = new AssemblyName();
assembly.Version = new Version(1, 0, 0, 0);
assembly.Name = "ReflectionEmitDelegateTest";
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.RunAndSave);
modbuilder = assemblyBuilder.DefineDynamicModule("MyModule", "ReflectionEmitDelegateTest.dll", true);
// Grab a method from somewhere, via Reflection, so we can emit a delegate that can hook up to it
MethodInfo targetMethod = Type.GetType("DelegateReflectionEmit.MyClass").GetMethod("MyConsoleWriteLineMethod");
// Create a delegate that has the same signature as the method we would like to hook up to
typeBuilder = modbuilder.DefineType("MyDelegateType", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(System.MulticastDelegate));
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) });
constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
// Grab the parameters of the method
ParameterInfo[] parameters = targetMethod.GetParameters();
Type[] paramTypes = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
paramTypes[i] = parameters[i].ParameterType;
}
// Define the Invoke method for the delegate
methodBuilder = typeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, targetMethod.ReturnType, paramTypes);
methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
// bake it!
Type t = typeBuilder.CreateType();
assemblyBuilder.Save("ReflectionEmitDelegateTest.dll");
}
}
}
The ILDASM output on ReflectionEmitDelegateTest.dll looks like this:
.class public auto autochar sealed MyDelegateType
extends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname
instance void .ctor(object A_1,
native int A_2) runtime managed
{
} // end of method MyDelegateType::.ctor
.method public hidebysig newslot virtual
instance void Invoke(string A_1) runtime managed
{
} // end of method MyDelegateType::Invoke
} // end of class MyDelegateType
Comments
- Anonymous
March 16, 2004
Eric also generates a delegate type at runtime, but the code looks much simpler, in this article: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp02172004.asp
The performance part is interesting too. - Anonymous
May 26, 2009
PingBack from http://castironbakeware.info/story.php?title=joel-pobar-s-clr-weblog-creating-delegate-types-via-reflection-emit