2009-08-30 9 views
5

Estoy trabajando en una rutina para usar DynamicMethod para recuperar valores de un objeto. Funcionó bien con la mayoría de los tipos de datos, a excepción de DateTime.Ticks, que es int64DynamicMethod devuelve un valor incorrecto cuando el tipo de propiedad es Int64

En la siguiente aplicación de prueba. Uso tanto MethodInfo como DynamicMethod, el métodoInfo devuelve el valor correcto pero DynamicMethod no. ¿Algunas ideas?

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

namespace ConsoleApplication2 
{ 
    public delegate object MemberGetDelegate(object obj); 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      DateTime dat = DateTime.Today; 
      PropertyInfo pi = typeof(DateTime).GetProperty("Ticks"); 
      MethodInfo mi = pi.GetGetMethod(); 
      Type type = pi.PropertyType; 
      object ticks = mi.Invoke(dat, new object[] { }); 
      Console.WriteLine("Get by MethodInfo " + ticks.ToString()); 

      MemberGetDelegate mget=TypeUtils.GetMemberFunc(pi); 
      object ret = mget(dat); 
      Console.WriteLine("Get by DynamicMethod " + ret.ToString()); 

      Console.Read(); 
     } 
    } 

    static class TypeUtils 
    { 
     public static readonly Type objectType = typeof(object); 
     public static readonly Type[] typeArray = new[] { typeof(object) }; 

     public static MemberGetDelegate GetMemberFunc(PropertyInfo pi) 
     { 

      MethodInfo mi = pi.GetGetMethod(); 

      if (mi != null) 
      { 
       DynamicMethod dm = new DynamicMethod("_" + mi.Name, 
                objectType, 
                typeArray, 
                pi.Module, true); 
       ILGenerator il = dm.GetILGenerator(); 

       // Load the instance of the object (argument 0) onto the stack 
       il.Emit(OpCodes.Ldarg_0); 

       // Call underlying get method 
       il.EmitCall(OpCodes.Callvirt, mi, null); 

       //boxing 
       if (pi.PropertyType.IsValueType) 
       { 
        il.Emit(OpCodes.Box, pi.PropertyType);     
       } 

       // return the value on the top of the stack 
       il.Emit(OpCodes.Ret); 

       return (MemberGetDelegate) dm.CreateDelegate(typeof (MemberGetDelegate)); 

      } 
      return null; 
     } 
    } 
} 
+0

¿Puede informarme de qué manera es incorrecto el resultado que obtiene? –

+0

Ejemplo de valores incorrectos: Obtener por propiedad 633871872000000000 Obtener por MethodInfo 633871872000000000 Obtener por DynamicMethod 3723350993856077580 –

+0

Gracias Lasse por publicar su resultado. Inicialmente pensé que era causado por el boxeo, así que cambié la firma del delegado y eliminé el código del boxeo, no ayudé, todavía estoy obteniendo el valor incorrecto. – Tony

Respuesta

4

Estás generando código inválido. Si se compila el IL resultante con ILASM

ldarg.0 
callvirt instance int64 [mscorlib]System.DateTime::get_Ticks() 
box int64 
ret 

y luego ejecutar PEVerify en el ejecutable, se le dirá que el código no es válido. (No puede usar callvirt en un método de tipo de valor así). El código de trabajo debe verse así

ldarg.0 
unbox [mscorlib]System.DateTime 
call instance int64 [mscorlib]System.DateTime::get_Ticks() 
box int64 
ret 

Adapte la generación de código en consecuencia y devolverá el valor correcto.

+0

Gracias, eso ayuda. Se agregó una lógica de unboxing y funcionó bien. il.Emit (OpCodes.Ldarg_0); // unboxing para el tipo de valor if (pi.PropertyType.IsValueType) { il.Emit (OpCodes.Unbox, pi.ReflectedType); } il.EmitCall (OpCodes.Callvirt, mi, null); // boxeo si (pi.PropertyType.IsValueType) { il.Emit (OpCodes.Box, pi.PropertyType); } – Tony

Cuestiones relacionadas