2009-04-02 3 views
3

Я создаю динамическое выражение, которое будет упорядочивать элементы в списке по некоторому правилу (лямбда-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); 

Может ли кто-нибудь помочь мне в этом?

ответ

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, а не два отдельных экземпляра даже с тем же именем, иначе вы получите: «Lambda Parameter not in scope» исключение без особого объяснения.

благодарит экспертов

0

Есть ли конкретная причина вы не просто звоните:

data.AsQueryable().OrderBy(exp); 

ли вам даже не нужно использовать IQueryable здесь? У меня такое чувство, что мне не хватает какой-то большой картины. Вы собираетесь называть это частью LINQ to SQL (или LINQ to Entities)? Если это только в LINQ to Objects, не можете ли вы просто использовать data.OrderBy(exp)?

В принципе, более какое-то объяснение было бы полезно :)

+0

вся картина следующая: Я хочу созд съел некоторый запрос (такие правила, как order, где, может быть, еще) на некоторые данные, которых у меня сейчас нет. Но я знаю его тип. Этот запрос позже будет отправлен на некоторые веб-службы, у которых есть данные и будет запускать запрос на нем. – Kamarey

+0

и забыл, это простой LINQ to Objects. – Kamarey

+0

Хорошо, теперь я смущен - если вы отправляете запрос в веб-службу, это не похоже на LINQ to Objects. Что вы хотите сделать заказ - веб-сервис или локальный процесс? –

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). Кроме этого ваше решение в порядке. Получите мой +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 
Смежные вопросы