2009-04-02 18 views
3

動的な式を作成しています。これは、あるルール(lambda exp。)でリスト内のアイテムを注文します。これはコードです:動的に作成された式

Expression<Func<String, String>> exp = o => o; 

MethodCallExpression orderByExp = Expression.Call(typeof(Enumerable), "OrderBy", 
    new Type[] { typeof(String), exp.Body.Type }, Expression.Parameter(typeof(IEnumerable<String>), "list"), exp); 

は今、私はそれをソートするために、特定のデータに以前に作成した式を実行したいが、それが理由のようないくつかの奇妙な例外の「ラムダパラメータのない範囲で」失敗したか、「引数の式が有効ではありません"

var data = new String[] { "asdasdasd", "asdads", "123", "xcvxcvs", "ASDSD" }; 

// one of attempts: doesn't work 
var result = data.AsQueryable().Provider.CreateQuery<String>(orderByExp); 

誰か助けてもらえますか?

data.AsQueryable().OrderBy(exp); 

は、あなたもここにIQueryableを使用する必要があります:

答えて

2

これは、作業コードです:

Expression<Func<String, String>> exp = o => o; 
var list = Expression.Parameter(typeof(IEnumerable<String>), "list"); 

MethodCallExpression orderByExp = Expression.Call(typeof(Enumerable), "OrderBy", 
    new Type[] { typeof(String), exp.Body.Type }, list, exp); 

var lambda = Expression.Lambda<Func<IEnumerable<String>, IEnumerable<String>>>(orderByExp, list); 
var data = new String[] { "asdasdasd", "asdads", "123", "xcvxcvs", "ASDSD" }; 
var result = lambda.Compile()(data); 
  1. あなたはラムダ式でそれをラップする必要があるMethodCallExpressionを実行します。
  2. MethodCallExpressionとLambdaExpressionを作成するときに同じパラメータ式( 'list')を使用し、同じ名前でも2つの別々のインスタンスを使用しないようにしてください。そうでなければ、 "Lambda Parameter in not scope"あまり説明がない例外です。

プロパティ(無反射)によって、任意の可算専門家

0

あなただけ呼び出していない特定の理由がありますか?私は大きな写真のいくつかが欠けていると感じる。実際にLINQ to SQL(またはLINQ to Entities)の一部としてこれを呼び出す予定ですか? LINQ to Objects内にある場合は、data.OrderBy(exp)を使用できませんか?

基本的には、いくつかのより多くの説明が参考になる:)

+0

画像全体が次にあります: 私はしたいです私は今持っていないいくつかのデータ(注文のようなルール、どこに他かもしれない)をいくつかのデータで食べました。しかし私はそのタイプを知っています。このクエリーは後でデータを持ついくつかのWebサービスに送信され、クエリーが実行されます。 – Kamarey

+0

と忘れてしまった、これはオブジェクトへの単純なLINQです。 – Kamarey

+0

さて、私は混乱しています - あなたがWebサービスにクエリを送信している場合、実際にLINQ to Objectsのようには聞こえません。何を注文したいのですか?Webサービス、またはローカルプロセスですか? –

3

ための感謝:

public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> items, string property, bool ascending) 
     { 
      var MyObject = Expression.Parameter(typeof (T), "MyObject"); 
      var MyEnumeratedObject = Expression.Parameter(typeof (IEnumerable<T>), "MyEnumeratedObject"); 
      var MyProperty = Expression.Property(MyObject, property); 
      var MyLamda = Expression.Lambda(MyProperty, MyObject); 
      var MyMethod = Expression.Call(typeof(Enumerable), ascending ? "OrderBy" : "OrderByDescending", new[] { typeof(T), MyLamda.Body.Type }, MyEnumeratedObject, MyLamda); 
      var MySortedLamda = Expression.Lambda<Func<IEnumerable<T>, IOrderedEnumerable<T>>>(MyMethod, MyEnumeratedObject).Compile(); 
      return MySortedLamda(items); 
     } 
+0

ええ、それは良い方法です。しかし、私の状況では、ソート/フィルタリングだけでなく、プロパティ名(私の例は、他の問題を説明するための単純なケース)よりも必要です。私はo => o.Users.Any(user => user.Type == 1)のような単純なラムダを実行する必要があります。これを除いて、あなたの解決策はOKです。私の+1を得る:) – Kamarey

1

は私が拡張機能を書くことにした、LINQのでの作業はほぼ同じ問題を抱えていたし、いくつかのアイデアはこの質問の回答から取られました:

<Extension()> _ 
Public Function OrderBy(Of T)(ByVal query As IEnumerable(Of T), ByVal sortColumn As String, ByVal direction As String) As IEnumerable(Of T) 
     Dim methodName As String = String.Format("OrderBy{0}", If(direction.ToLower() = "asc", "", "Descending")) 
     Dim parameter As ParameterExpression = Expression.Parameter(GetType(T), "p") 
     Dim memberAccess As MemberExpression = Nothing 

     For Each _property As Object In sortColumn.Split(".") 
      memberAccess = MemberExpression.Property(If(memberAccess, CType(parameter, Expression)), _property) 
     Next 

     Dim orderByLambda As LambdaExpression = Expression.Lambda(memberAccess, parameter) 
     ' 
     Dim myEnumeratedObject As ParameterExpression = Expression.Parameter(GetType(IEnumerable(Of T)), "MyEnumeratedObject") 

     Dim result As MethodCallExpression = Expression.Call(GetType(Enumerable), _ 
        methodName, _ 
        New System.Type() {GetType(T), memberAccess.Type}, _ 
        myEnumeratedObject, _ 
        orderByLambda) 

     Dim lambda = Expression.Lambda(Of Func(Of IEnumerable(Of T), IEnumerable(Of T)))(result, myEnumeratedObject) 
     Return lambda.Compile()(query) 
    End Function 
関連する問題