C#: IL/Emit: DynamicMethod and DateTime problem

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • joasi
    New Member
    • Jul 2008
    • 2

    C#: IL/Emit: DynamicMethod and DateTime problem

    Hi,
    I am working in C# with an Object / Relational Database mapping framework, where I want to generate method calls based on string representation of the call signature.
    I have used reflection and Method-/Field-/PropertyInfo invokation to do this, but now I want to make the calls faster by using Emit and DynamicMethods

    I am now trying to create a factory method that creates a dynamic method as a "wrapper" around a method call with no arguments.
    The type of object to call the method on is passed as a parameter to the dynamicMethod factory method
    The name of the method to wrap is passed as a string, by which I get the MethodInfo-object for the method.
    The generated dynamic method is returned as a delegate, which I later invoke with the particular object that I want to call the wrapped method on.

    The solution seems to work fine except for DateTime: If I pass DateTime as the type and "ToShortDateStr ing()" as the method signature I get a completely different datetime-string than expected: for example "6884-12-07" instead of 2008 something.

    The code I use to generate the dynamic method is as follows:

    Code:
    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    ...
    Code:
    public delegate object GetHandler(object source);
    
    internal static GetHandler CreateGetHandler(Type type, MethodInfo methodInfo)
    {
       DynamicMethod dynamicGet = CreateGetDynamicMethod(type, methodInfo.Name);
       ILGenerator getGenerator = dynamicGet.GetILGenerator();
       getGenerator.Emit(OpCodes.Ldarg_0);
       getGenerator.Emit(OpCodes.Call, methodInfo);
       getGenerator.Emit(OpCodes.Ret);
       return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
    }
    ...
    Code:
    private static DynamicMethod CreateGetDynamicMethod(Type type, string name)
    {
       return new DynamicMethod("Dynamic" + name, typeof(object), new Type[] { typeof(object) }, type, true);
    }
    I have tried box/unboxing argument and return value without any effect. Can anyone see what I am doing wrong or is this a bugg in DateTime or Emit?

    Thanks,

    /Joakim
  • joasi
    New Member
    • Jul 2008
    • 2

    #2
    After a lot of trial and error I found the answer:

    Any ValueType-object that is passed boxed as an object to the DynamicMethod factory has to be (in IL) first loaded to the stack as a value from the argument, then unboxed, then stored to a local variable declared as the ValueType, and finally loaded as a reference to the stack.
    Then the method call can be invoked on the boxed object reference.

    this is the code I came up with:

    Code:
    internal static GetHandler CreateGetHandler(Type type, MethodInfo methodInfo)
    {
       DynamicMethod dynamicGet = CreateGetDynamicMethod(type, methodInfo.Name);
       ILGenerator getGenerator = dynamicGet.GetILGenerator();
       getGenerator.Emit(OpCodes.Ldarg_0);
       if (type.IsValueType)
       {
          getGenerator.DeclareLocal(type);
          getGenerator.Emit(OpCodes.Unbox_Any, type);
          getGenerator.Emit(OpCodes.Stloc_0);
          getGenerator.Emit(OpCodes.Ldloca_S, 0);
       }
       getGenerator.Emit(OpCodes.Callvirt, methodInfo);
       if (methodInfo.ReturnType.IsValueType)
       {
          getGenerator.Emit(OpCodes.Box, methodInfo.ReturnType);
       }
       getGenerator.Emit(OpCodes.Ret);
       return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
    }

    Comment

    • Alxandr

      #3
      Sorry to tell you, but you can skipp the storing and loading, and only do the unboxing. I've written a tutorial on it here: http://alxen.wordpress.com/2010/10/1...t-and-opcodes/

      Comment

      Working...