Поделиться через


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