2009-08-30 4 views
5

Je travaille sur une routine pour utiliser DynamicMethod pour extraire des valeurs d'un objet. Il a bien fonctionné avec la plupart des types de données, sauf pour DateTime.Ticks, qui est int64DynamicMethod renvoie une valeur incorrecte lorsque le type de propriété est Int64

Dans l'application de test suivante. J'utilise MethodInfo et DynamicMethod, methodInfo renvoie la valeur correcte mais DynamicMethod non. Des idées?

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

Pouvez-vous nous indiquer de quelle manière le résultat est incorrect? –

+0

Exemple de valeurs incorrectes: Get by property 633871872000000000 Get de MethodInfo 633871872000000000 Get de DynamicMethod 3723350993856077580 –

+0

Merci d'avoir posté votre résultat. J'ai d'abord pensé qu'il était causé par la boxe, alors j'ai changé la signature du délégué et j'ai supprimé le code de boxe, je n'ai pas aidé, je reçois toujours la valeur incorrecte. – Tony

Répondre

4

Vous générez du code invalide. Si vous compilez le résultat IL avec ilasm

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

Et puis exécutez PEVerify sur l'exécutable, il vous dira que le code est invalide. (Vous ne pouvez pas utiliser callvirt sur une méthode de type valeur comme ça). Le code de travail doit ressembler à ceci

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

Adaptez votre génération de code en conséquence et la valeur correcte sera retournée.

+0

Merci, ça aide. Ajout de la logique de déballage et cela a bien fonctionné. il.Emit (OpCodes.Ldarg_0); // unboxing pour le type de valeur if (pi.PropertyType.IsValueType) { il.Emit (OpCodes.Unbox, pi.ReflectedType); } il.EmitCall (OpCodes.Callvirt, mi, null); // boxe si (pi.PropertyType.IsValueType) { il.Emit (OpCodes.Box, pi.PropertyType); } – Tony

Questions connexes