2009-08-30 14 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

あなたは結果が間違ってどのように報告されますか? –

+0

不適切な値の例:プロパティで取得する633871872000000000 Get MethodInfo 633871872000000000 Get Get DynamicMethod 3723350993856077580 –

+0

結果を投稿していただきありがとうございます。 私は最初はボクシングによって引き起こされたと考えていたので、代理人の署名を変更し、ボクシングコードを削除しました。私は助けなかった、私はまだ間違った価値を得ています。 – Tony

答えて

4

無効なコードが生成されています。あなたはILASM

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

と結果のILをコンパイルし、実行可能にするPEverifyを実行した場合、それはコードが無効であることを教えてくれます。 (あなたはそのような値型のメソッドでcallvirtを使うことはできません)。作業コードは次のようになります

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

適切なコード生成を行い、正しい値を返します。

+0

ありがとう、それは役立ちます。 unboxingロジックを追加し、うまくいきました。 il.Emit(OpCodes.Ldarg_0); //値タイプのアンボックス。 if(pi.PropertyType.IsValueType) { il.Emit(OpCodes.Unbox、pi.ReflectedType); } il.EmitCall(OpCodes.Callvirt、mi、null); //ボクシングIF(pi.PropertyType.IsValueType) {il.Emit(OpCodes.Box、pi.PropertyType)。 } – Tony

関連する問題