2009-08-30 3 views
5

Sto lavorando a una routine per utilizzare DynamicMethod per recuperare i valori da un oggetto. Ha funzionato bene con la maggior parte dei tipi di dati, ad eccezione di DateTime.Ticks, che è int64DynamicMethod restituisce un valore errato quando il tipo di proprietà è Int64

Nella seguente app di test. Io utilizzo sia MethodInfo che DynamicMethod, il metodoInfo restituisce il valore corretto ma DynamicMethod no. Qualche idea?

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

Puoi per favore segnalare in che modo il risultato non è corretto che ottieni? –

+0

Esempio di valori errati: Get by property 633871872000000000 Get by MethodInfo 633871872000000000 Get by DynamicMethod 3723350993856077580 –

+0

Grazie Lasse per la pubblicazione del risultato. Inizialmente pensavo che fosse causato dal pugilato, quindi ho cambiato la firma del delegato e rimosso il codice box, non ho aiutato, sto ancora ottenendo il valore errato. – Tony

risposta

4

Stai generando codice non valido. Se si compila il IL risultante con ILASM

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

e quindi eseguire PEVerify sul file eseguibile, che vi dirà che il codice non è valido. (Non è possibile utilizzare callvirt su un metodo di tipo valore come quello). Il codice di lavoro dovrebbe assomigliare a questo

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

Adattare la generazione del codice di conseguenza e restituirà il valore corretto.

+0

Grazie, questo aiuta. Aggiunta la logica di unboxing e ha funzionato bene. il.Emit (OpCodes.Ldarg_0); // unboxing per il tipo di valore if (pi.PropertyType.IsValueType) { il.Emit (OpCodes.Unbox, pi.ReflectedType); } il.EmitCall (OpCodes.Callvirt, mi, null); // boxe se (pi.PropertyType.IsValueType) { il.Emit (OpCodes.Box, pi.PropertyType); } – Tony