What's wrong with the IL I am emitting in Reflection.Emit.DynamicMethod?

Ideally I want to use a delegate CreateObject

because the code that generates these dynamic methods is for a deserializer that should be able to handle any type (at least primitives, structures and class instances). However, I got a problem with the delegate type CreateObject

, so I decided to try a delegate CreateRectangle

to debug things. I got a little closer to a working solution, but something else is not right. What's wrong with my code for both cases? That is, how can I get the dynamic method to work for CreateObject

both CreateRectangle

? Or is my calling code the culprit?

Output:

{X=0,Y=0,Width=0,Height=0}

Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

Exception has been thrown by the target of an invocation.
    Common Language Runtime detected an invalid program.

      

code:

using System;
using System.Drawing;
using System.Reflection.Emit;

namespace Experiments {
    public class Program {
        private delegate object CreateObject();
        private delegate Rectangle CreateRectangle();

        static void Main() {
            Console.WriteLine(new Rectangle());
            Console.WriteLine();
            var dm = BuildDynamicMethod();
            TryCreateDelegate<CreateObject>(dm);
            Console.WriteLine();
            TryCreateDelegate<CreateRectangle>(dm);
            Console.WriteLine();
            Console.ReadKey();
        }

        private static void TryCreateDelegate<T>(DynamicMethod dm) {
            try {
                var co = dm.CreateDelegate(typeof (T));
                var value = co.DynamicInvoke(null);
                Console.WriteLine(value);
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
                var indent = 0;
                while (ex.InnerException != null) {
                    indent++;
                    ex = ex.InnerException;
                    Console.WriteLine(new string('\t', indent) + ex.Message);
                }
            }
        }

        private static DynamicMethod BuildDynamicMethod() {
            var tr = typeof(Rectangle);
            var dm = new DynamicMethod("buildNewRectangle", tr, Type.EmptyTypes);
            var il = dm.GetILGenerator();
            il.Emit(OpCodes.Ldloca_S, (byte)0);
            il.Emit(OpCodes.Initobj, tr);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Box, tr);
            il.Emit(OpCodes.Ret);
            return dm;
        }
    }
}

      

+3


source to share


2 answers


private delegate object CreateObject();
private delegate Rectangle CreateRectangle();

static void Main()
{
  Console.WriteLine(new Rectangle());
  Console.WriteLine();
  TryCreateDelegate<CreateObject>(BuildDynamicMethod_Boxed());
  Console.WriteLine();
  TryCreateDelegate<CreateRectangle>(BuildDynamicMethod());
  Console.WriteLine();
}

private static DynamicMethod BuildDynamicMethod_Boxed()
{
  var TRect = typeof(Rectangle);
  var dm = new DynamicMethod("buildNewRectangle", typeof(object), Type.EmptyTypes);
  var il = dm.GetILGenerator();
  il.Emit(OpCodes.Ldloca_S, il.DeclareLocal(TRect));
  il.Emit(OpCodes.Initobj, TRect);
  il.Emit(OpCodes.Ldloc_0);      
  il.Emit(OpCodes.Box, TRect);
  il.Emit(OpCodes.Ret);
  return dm;
}

private static DynamicMethod BuildDynamicMethod()
{
  var TRect = typeof(Rectangle);
  var dm = new DynamicMethod("buildNewRectangle", TRect, Type.EmptyTypes);
  var il = dm.GetILGenerator();
  il.Emit(OpCodes.Ldloca_S, il.DeclareLocal(TRect));
  il.Emit(OpCodes.Initobj, TRect);
  il.Emit(OpCodes.Ldloc_0);
  il.Emit(OpCodes.Ret);
  return dm;
}

private static void TryCreateDelegate<T>(DynamicMethod dm)
{
  try
  {
    var co = dm.CreateDelegate(typeof(T));
    var value = co.DynamicInvoke();
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
    var indent = 0;
    while (ex.InnerException != null)
    {
      indent++;
      ex = ex.InnerException;
      Console.WriteLine(new string('\t', indent) + ex.Message);
    }
  }
}

      



+3


source


I found the easiest way to understand what a valid ILCode is is to start by writing C # code, compiling it and then trying to read the decompiled ILCode. This can be very informative.

But it looks like you are trying to refer to local variables without declaring an address space for anyone. LdLoca_S refers to a local variable, and before you can do that, you need to call .DeclareLocal (tr). Not sure if this is the only problem, but it is the most obvious one.



Edit: OK, I ran it myself and it does work when you add .DeclareLocal (tr) there, but there was also a problem with the method signature.

But you are trying to call it with two different method signatures. If you return an object you need to insert it, but if you return a Rectangle you cannot insert it. But your return type is hardcoded to typeof (Rectangle). So you are trying to insert a rectangle and then return the rectangle as a rectangle. Either don't paste it or change the return type.

+3


source







All Articles