2009-08-30 33 views
5

我正在使用DynamicMethod從對象檢索值的例程上工作。它適用於大多數數據類型,除了DateTime.Ticks,它是int64當屬性類型爲Int64時,DynamicMethod返回不正確的值

在以下測試應用程序中。我同時使用MethodInfo和DynamicMethod,methodInfo返回正確的值,但DynamicMethod不會。有任何想法嗎?

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

您能否以您的結果不正確的方式報告? – 2009-08-30 17:24:45

+0

錯誤值的示例:獲取屬性633871872000000000 獲取方法信息633871872000000000 獲取DynamicMethod 3723350993856077580 – 2009-08-30 17:37:56

+0

感謝Lasse發佈您的結果。 我最初認爲這是造成拳擊,所以我改變了委託人的簽名和刪除了拳擊代碼,我沒有幫助,我仍然得到不正確的值。 – Tony 2009-08-30 18:27:19

回答

4

您正在生成無效的代碼。如果你用Ilasm編譯得到的IL,那麼

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

然後在可執行文件上運行PEVerify,它會告訴你代碼是無效的。 (你不能像這樣的值類型方法使用callvirt)。工作的代碼看起來應該是這樣

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

相應地調整代碼生成,它會返回正確的值。

+0

謝謝,這有幫助。增加了拆箱邏輯,它工作正常。 il.Emit(OpCodes.Ldarg_0); //拆箱值類型 如果(pi.PropertyType.IsValueType) { il.Emit(OpCodes.Unbox,pi.ReflectedType); } il.EmitCall(OpCodes.Callvirt,mi,null);如果(pi.PropertyType.IsValueType) il.Emit(OpCodes.Box,pi.PropertyType); } – Tony 2009-08-31 16:19:37

相關問題