2016-08-16 7 views
1

私はクラス内のすべてのフィールドに対して静的なリフレクションを実装しようとしています。 つまり、これらのすべてのフィールドの名前を使用してgetおよびsetを作成する必要があります。type.GetFields()の静的(式)の代替

は、私は今、私はこれらの2つの問題を持っているSet field value with Expression treeに答えを使用して、以下のソリューション

public class ExpressionSetterGetter 
    { 
     public class SetterGetter<T> where T : class 
     { 
      public Delegate getter; 
      public Action<T, object> setter; 
     } 

     public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>() where T : class 
     { 

      var dic = new Dictionary<string, SetterGetter<T>>(); 
      SetterGetter<T> setterGetter; 

      var type = typeof(T); 
      var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 
      foreach (var fieldInfo in fields) 
      { 
       var targetExp = Expression.Parameter(type, "target"); 
       var valueExp = Expression.Parameter(typeof(object), "value"); 
       var fieldExp = Expression.Field(targetExp, fieldInfo); 
       var assignExp = Expression.Assign(fieldExp, Expression.Convert(valueExp, fieldExp.Type)); 
       var fieldSetter = Expression.Lambda<Action<T, object>>(assignExp, targetExp, valueExp).Compile(); 

       ParameterExpression objParm = Expression.Parameter(type, "obj"); 
       MemberExpression fieldExpr = Expression.Field(objParm, fieldInfo.Name); 
       var fieldExprConverted = Expression.Convert(fieldExpr, typeof(object)); 
       var fieldGetter = Expression.Lambda(fieldExprConverted, objParm).Compile(); 

       setterGetter = new SetterGetter<T>() { setter = fieldSetter, getter = fieldGetter }; 

       dic.Add(fieldInfo.Name, setterGetter); 
      } 
      return dic; 
     } 
    } 

に来ました。

  1. 私はtype.GetFields()を使用しますが、MSDNには、それは反射法であると言います。 コンパイラが実行時の前に型を知らないことを意味します。 私はそうですか?正しい場合は、 式ツリーを使用する理由は何ですか。私が知っている限り、式ツリーはコンパイル時に コードに変換されますが、ほとんど追加コストがかかりません。

  2. 同じロジックです。どのようなラップする必要があるフィールドの名前を の名前のリストにパラメータとして配置する場合はどうなりますか。つまり、 の代わりにtype.GetFields()を使用すると、フィールドの名前をパラメータとして渡すだけです。

    public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>(IEnumerable<string> fieldNames

    明らか

、リストはコンパイル時に知られていないことができます。繰り返しますが、CLRはどのように反応しますか?

+0

CLRは式ツリーが何であるかを知りません。それは誰でも書くことができる単なる図書館です。 – usr

答えて

1
  1. 式ツリー出力は、コンパイル時には知られていないで、彼らは違う何かがある、実行時にコンパイルをしています。表現木のコンパイルを使うことの利点は、リフレクション・ヘビー・リフティングが、式の構築とコンパイル中に一度だけ実行されることです。そこから、結果として得られるデリゲートの呼び出しは非常に高速です。
  2. リストに実際にクラスに存在するフィールドのみが指定され、すべてのフィールドのサブセットのみを指定する場合は、理論上、リフレクションのパフォーマンスへの影響を多少減らすことができます。しかし、リフレクションを使用してのみ取得できるそれぞれのインスタンスには、FieldInfoのインスタンスが必要になることに注意してください。だから、既知のフィールドごとにGetFieldを呼び出す全体的な価格は、おそらくすべてのフィールドに対してGetFieldsを呼び出すよりもさらに高いでしょう。

フィールド値をコンパイル時に設定する最も簡単な方法は、プライベートフィールドをパブリックプロパティに変換することです。次に、あなたが望むようにそれらを設定することができます。

これはあなたの冗談ではなく、違いの説明です - C#では、リフレクションAPIを使用する場合を除いて、フィールドを外部から設定することはできません。これらのAPIはコンパイル時ではなく実行時に設計されています。

コンパイル時(正確にはコンパイル後)に規則を曲げて作成する場合は、PostSharpFodyなどのサードパーティライブラリを使用する必要があります。

これは、現在のバージョンまたは以前のバージョンのいずれかでC#を使用している限り、ストーリーの終わりです。

+0

あなたの答えをありがとう。あなたはC#で表現や(多分)他の機能的なものを構築する方法を読むことができる本を知っていますか? まだリフレクションよりはるかに優れていますが、コンパイル時にそれを行う可能性について尋ねなければなりません。 私はクラスについてすべてを知っていると仮定します。たとえば、上記のようにすべての開いているフィールドに対して動的なデリゲートを作成したいとします。 コンパイラがコンパイル時にそれをしない理由は何ですか?その背後にCLR制限やロジックがありますか? –

+0

@SimonS私は私の答えに多くの説明を加えた – galenus

関連する問題