2016-01-12 11 views
6

シリアライズの目的で、オブジェクトのプロパティ値を即座に更新し、後で使用できるようにリストに格納するデリゲートを生成しようとしています。 構造体を逆シリアル化しようとしない限り、すべてうまく動作します。Open Delegateを使用して構造体プロパティーにアクセスする

我々はオープン委譲については、この記事で私たちのコードをベース:http://codeblog.jonskeet.uk/2008/08/09/making-reflection-fly-and-exploring-delegates/

そしてここでは、クラスベースのオブジェクトのプロパティのセッターに対処する私たちのコードです。

private static System.Action<object, object> ToOpenActionDelegate<T, TParam>(System.Reflection.MethodInfo methodInfo) where T : class 
    { 
     System.Type parameterType = typeof(TParam); 

     // Convert the slow MethodInfo into a fast, strongly typed, open delegate 
     System.Action<T, TParam> action = (System.Action<T, TParam>)System.Delegate.CreateDelegate(typeof(System.Action<T, TParam>), methodInfo); 

     // Convert the strong typed delegate into some object delegate! 
     System.Action<object, object> ret = (object target, object param) => action(target as T, (TParam)System.Convert.ChangeType(param, parameterType)); 

     return ret; 
    } 

あなたが推測したように、それは構造体では機能しません。 この投稿は、オープンデリゲートを構造体で処理する方法について話しています。 How can I create an open Delegate from a struct's instance method? (実際には、これよりもポストの方が多く見つかりましたが、これにはILコードの生成を使用しない単純なソリューションがあります。 ..)

しかし、今のところ、refパラメータを使用してプロパティ設定ツールのmethodinfoをデリゲートにバインドしようとするたびに、例外が発生します。ここ は、私が使用して現在のコードです:

public delegate void RefAction<T, TParam>(ref T arg, TParam param) where T : class; 
    private static RefAction<object, object> ToOpenActionDelegate<T, TParam>(System.Reflection.MethodInfo methodInfo) where T : class 
    { 
     // Convert the slow MethodInfo into a fast, strongly typed, open delegate 
     System.Type objectType = typeof(T); 
     System.Type parameterType = typeof(TParam); 
     RefAction<object, object> ret; 
     if (objectType.IsValueType) 
     { 
      RefAction<T, TParam> propertySetter = (RefAction<T, TParam>)System.Delegate.CreateDelegate(typeof(RefAction<T, TParam>), methodInfo); 

      // we are trying to set some struct internal value. 
      ret = (ref object target, object param) => 
      { 
       T boxed = (T)target; 
       propertySetter(ref boxed, (TParam)System.Convert.ChangeType(param, parameterType)); 
       target = boxed; 
      }; 
     } 
     else 
     { 
      System.Action<T, TParam> action = (System.Action<T, TParam>)System.Delegate.CreateDelegate(typeof(System.Action<T, TParam>), methodInfo); 
      ret = (ref object target, object param) => action(target as T, (TParam)System.Convert.ChangeType(param, parameterType)); 
     } 

     return ret; 
    } 

次の行を実行するときに問題が表示されます。

RefAction<T, TParam> propertySetter = (RefAction<T, TParam>)System.Delegate.CreateDelegate(typeof(RefAction<T, TParam>), methodInfo); 

本当に、少なくとも私にとっては、リンクで使用されるものと同じです

SomeMethodHandler d = (SomeMethodHandler)Delegate.CreateDelegate(typeof(SomeMethodHandler), method); 

delegate int SomeMethodHandler(ref A instance); 
public struct A 
{ 
    private int _Value; 

    public int Value 
    { 
     get { return _Value; } 
     set { _Value = value; } 
    } 

    private int SomeMethod() 
    { 
     return _Value; 
    } 
} 
上記のポスト

誰も私の側ではなく、リンクされたスレッドで例外を生成する理由についてのアイデアを持っていますか? C#ランタイムバージョンにリンクされていますか?私は単一性のため、3.5にほぼ相当するモノフレームワークです。

とにかく、読んでいただきありがとうございます。私が質問レイアウトや構文で何か間違っていたら躊躇しないでください!

乾杯、 flo。

+0

をどのようにあなたのメソッドを呼び出していますか? 'T'は参照型でなければならないので、' 'で呼び出すことはできません。 – Alexey

答えて

1

オープンデリゲートの代わりに静的メソッドへのデリゲートを作成しています。 (私は二重のボクシング/アンボクシングで、しかし、パフォーマンスに関するのでわからない)私はあなたのCreateDelegate通話にnullを追加し、それが働いた:

public struct S 
{ 
    public string Value {get; set;} 
} 

static class Program 
{ 

    public delegate void RefAction<T, TParam>(ref T arg, TParam param); 
    static RefAction<object, object> ToOpenActionDelegate<T, TParam>(System.Reflection.MethodInfo methodInfo) 
    { 
     // Convert the slow MethodInfo into a fast, strongly typed, open delegate 
     Type objectType = typeof(T); 
     Type parameterType = typeof(TParam); 
     RefAction<object, object> ret; 
     if (objectType.IsValueType) 
     { 
      RefAction<T, TParam> propertySetter = (RefAction<T, TParam>)Delegate.CreateDelegate(typeof(RefAction<T, TParam>), null, methodInfo); 

      // we are trying to set some struct internal value. 
      ret = (ref object target, object param) => 
      { 
       T boxed = (T)target; 
       propertySetter(ref boxed, (TParam)System.Convert.ChangeType(param, parameterType)); 
       target = boxed; 
      }; 
     } 
     else 
     { 
      Action<T, TParam> action = (Action<T, TParam>)Delegate.CreateDelegate(typeof(Action<T, TParam>), null, methodInfo); 
      ret = (ref object target, object param) => action((T)target, (TParam)System.Convert.ChangeType(param, parameterType)); 
     } 

     return ret; 
    } 

    public static void Main(string[] args) 
    { 
     var s = new S(); 

     var mi = s.GetType().GetMethod("set_Value"); 
     /* 
     var deleg = (RefAction<S, string>)Delegate.CreateDelegate(typeof(RefAction<S, string>), null, mi); 

     deleg(ref s, "hello"); 

     RefAction<object, object> deleg2 = (ref object target, object param) => { 
      S boxed = (S)target; 
      deleg(ref boxed, (string)param); 
      target = boxed; 
     }; 
     */ 

     RefAction<object, object> deleg2 = ToOpenActionDelegate<S, string>(mi); 

     var o = (object)s; 

     deleg2(ref o, "world"); 

     s = (S)o; 

     Console.WriteLine(s.Value); //prints "world" 

     Console.ReadKey(true); 
    } 
} 
+0

答えをありがとう。私はあなたのコードを試して、それは動作します。しかし、それは私のアプリケーションでそれを使用するときはまだありません。私は戻ってくる前にさらにプッシュしようとしますが、まだ私に希望を持ってくれてありがとう!乾杯! flo –

+0

私は時間をかけて、新しいVisualプロジェクトで完全な制作コードをコピーしました。すべてが魅力的です。 "Monodevelop"でも動作します。しかし、いったんUnityで "TestProject"と全く同じことをしたら、 "メソッド引数が互換性がない"ためクラッシュします。私はこれをUnityに報告し、ベストを願っています。回避策についてのご意見はありますか? –

+0

@ThorTillasいいえ。 Unityはかなり古いバージョンのMonoを使用していますので、何が間違っているのかはわかりません。特に、コードが非常に多くのフープを飛び越えるからです。 – Alexey

関連する問題