2017-03-01 6 views
-1

(動的LINQ式を作成するには)。 DataIntArrayEqualityComparerリフレクションにLINQの式を変換する方法を、私は三つのクラスを作成しました

public class Data 
    { 
     public Dictionary<int[], List<double>> s = new Dictionary<int[], List<double>>(new IntArrayEqualityComparer());   

     public Data() 
     { 
     } 

     public Data(Dictionary<int[], List<double>> s) 
     { 
      this.s = s; 
     } 

     public Dictionary<int[], List<double>> S 
     { 
      get { return s; } 
      set { s = value; } 
     } 
    } 

public class IntArrayEqualityComparer : IEqualityComparer<int[]> 
    { 
     public bool Equals(int[] x, int[] y) 
     { 
      if (x.Length != y.Length) 
      { 
       return false; 
      } 
      for (int i = 0; i < x.Length; i++) 
      { 
       if (x[i] != y[i]) 
       { 
        return false; 
       } 
      } 
      return true; 
     } 

     public int GetHashCode(int[] obj) 
     { 
      int result = 17; 
      for (int i = 0; i < obj.Length; i++) 
      { 
       unchecked 
       { 
        result = result * 23 + obj[i]; 
       } 
      } 
      return result; 
     } 
    } 

below-私は反射にLINQ式を変換する必要のあるExpressionが作成された名前の第三のクラスです 2つのクラス -

public class Expresion 
    { 
     public void CreateExpression() 
     { 
      Expression<Func<Data, List<int>>> exp1 = null; 
      //Below is the LINQ expression I want to convert 
      exp1 = p2 => p2.s[new int[] { 14, 5 }].Select((item, index) => new { item, index }).Select(x => x.index).ToList(); 

      ParameterExpression p1 = Expression.Parameter(typeof(Data), "p"); 
      MethodInfo mInfo = typeof(List<double>).GetMethod("get_Item"); 
      MethodInfo mInfo1 = typeof(Dictionary<int, List<double>>).GetMethod("get_Item"); 
      MethodInfo mInfo2 = typeof(Dictionary<int[], List<double>>).GetMethod("get_Item"); 
      MethodInfo mInfo3 = typeof(List<int[]>).GetMethod("get_Item"); 

      MemberExpression s1 = Expression.Property(p1, "s"); 
      ParameterExpression index1 = Expression.Parameter(typeof(int), "index"); 
      ParameterExpression item1 = Expression.Parameter(typeof(double), "item"); 

      //Here I want to covert the "(item, index) => new { item, index }" part from LINQ expression into Reflection 
     } 
    } 
+0

私は '「get_Item」' 'MethodInfo'オブジェクトとして、あなたはおそらく' GetIndexParameters'はカウントを持っているものを見つけることによって、インデクサー 'PropertyInfo'を見つける必要がありますに依存しないでしょう。それだけでも私です。適切なオーバーロードでEnumerable.Selectからジェネリックメソッド呼び出しを作成する必要がある場合は、ラムダ式(あなたのanon型のニュース)を作成し、それを渡します。問題は例をここで見ることができ、あなたの匿名型を構築されます。http://stackoverflow.com/a/3740637/491907 – pinkfloydx33

+1

余談、プロヒント:書き込み '式> EXP = P2 => ..それ以降にブレークポイントを設定します。次に、デバッガを使用して 'exp'の' DebugView' "プロパティ"を検査し、それがどのように構築されているかを確認します。この場合は動作しないかもしれませんが、間違いなく役立つことがあります。また、読めるように少し簡単にインストールできる他のExpression Visualizesもあります。 – pinkfloydx33

+0

あなたは物事を複雑にするかもしれません。実行しているすべてがインデックスを選択している場合は、実際には匿名型は必要ありません。 2番目に連鎖した 'Select'を削除して、最初のインデックスでintとしてインデックスを返します。 – pinkfloydx33

答えて

0

おそらく最も複雑で、役に立たないExpressionツリーI手で造られた。コメントインライン。

public class Expresion { 
    // We need the anonymous type that we want to use 
    private static readonly Type AnonymousType = new { item = 0.0, index = 0 }.GetType(); 

    public void CreateExpression() { 
     //Below is the LINQ expression I want to convert 
     Expression<Func<Data, List<int>>> exp2 = p => p.s[new int[] { 14, 5 }].Select((item, index) => new { item, index }).Select(x => x.index).ToList(); 

     ParameterExpression p1 = Expression.Parameter(typeof(Data), "p"); 

     MemberExpression s1 = Expression.PropertyOrField(p1, "s"); 

     // The indexer 
     PropertyInfo dictItem = s1.Type.GetProperty("Item"); 

     // The key to the dictionary, new int[] { 14, 5 } 
     var key = Expression.NewArrayInit(typeof(int), Expression.Constant(14), Expression.Constant(5)); 

     // s[new int[] { 14, 5 }] 
     var getItem = Expression.Property(s1, dictItem, key); 

     // Enumerable.Select with indexer (generic) 
     var enumerableSelectIndexTSourceTResult = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) 
                where x.Name == "Select" && x.IsGenericMethod 
                let args = x.GetGenericArguments() 
                where args.Length == 2 
                let pars = x.GetParameters() 
                where pars.Length == 2 && 
                 pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) && 
                 pars[1].ParameterType == typeof(Func<,,>).MakeGenericType(args[0], typeof(int), args[1]) 
                select x).Single(); 

     // Enumerable.Select with indexer (non-generic) 
     var enumerableSelectIndex = enumerableSelectIndexTSourceTResult.MakeGenericMethod(typeof(double), AnonymousType); 

     // Inner function start 
     ParameterExpression item1 = Expression.Parameter(typeof(double), "item"); 
     ParameterExpression index1 = Expression.Parameter(typeof(int), "index"); 

     var innerExpression1 = Expression.Lambda(Expression.New(AnonymousType.GetConstructors().Single(), item1, index1), item1, index1); 

     // .Select((item, index) => new { item, index }) 
     var select1 = Expression.Call(enumerableSelectIndex, getItem, innerExpression1); 
     // Inner function end 

     // Enumerable.Select without indexer (generic) 
     var enumerableSelectTSourceTResult = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) 
               where x.Name == "Select" && x.IsGenericMethod 
               let args = x.GetGenericArguments() 
               where args.Length == 2 
               let pars = x.GetParameters() 
               where pars.Length == 2 && 
                pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) && 
                pars[1].ParameterType == typeof(Func<,>).MakeGenericType(args[0], args[1]) 
               select x).Single(); 

     // Enumerable.Select without indexer (non-generic) 
     var enumerableSelect = enumerableSelectTSourceTResult.MakeGenericMethod(AnonymousType, typeof(int)); 

     // Inner function start 
     ParameterExpression anonymousType1 = Expression.Parameter(AnonymousType, "x"); 
     var innerExpression2 = Expression.Lambda(Expression.Property(anonymousType1, "index"), anonymousType1); 
     // Inner function end 

     // .Select((previous select), x => x.index) 
     var select2 = Expression.Call(enumerableSelect, select1, innerExpression2); 

     // Enumerable.ToList (generic) 
     var enumerableToListTSource = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) 
             where x.Name == "ToList" && x.IsGenericMethod 
             let args = x.GetGenericArguments() 
             where args.Length == 1 
             let pars = x.GetParameters() 
             where pars.Length == 1 && 
              pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) 
             select x).Single(); 

     // Enumerable.ToList (non-generic) 
     var enumerableToList = enumerableToListTSource.MakeGenericMethod(typeof(int)); 

     // .ToList((previous select)) 
     var toList1 = Expression.Call(enumerableToList, select2); 

     var exp1 = Expression.Lambda<Func<Data, List<int>>>(toList1, p1); 
     var func1 = exp1.Compile(); 

     // Test 
     var data = new Data(); 
     data.S[new int[] { 14, 5 }] = new List<double> { 1.0, 2.0 }; 
     var result = func1(data); 
    } 
} 

いくつかの制限があります。使用される匿名型はコンパイル時に知っている必要があります。多くの場合、Tuple<>を使用する方法があります。コード内のType AnonymousType行は、コンパイラに型を知らせ、最終的に(.GetType()を通して)取得します。

もう一つの重要な部分はEnumerableクラス内の関数を見つけることについてです。 Selectは、同じ数のパラメータを持つ2つの異なるSelectが存在するため、特に見つけるのがかなり複雑です。

+0

iがExpresssion以下にLINQクエリの上方に変更する必要がある: 'EXP1 = P2 => p2.s [新しいINT [] {14、5}]((項目、指数)=>新しい{アイテム、インデックスを})を選択します。 (x => x.index> 2).Select(x => x.index).ToList(); ' LINQ表現の' where'部分をリフレクションに変換する方法。 –

+1

@grishmashah私がここで採用している基本的なルールは:1つの質問です。質問は特に6日後に変更されません。 – xanatos

関連する問題