Динамически созданные выражения - PullRequest
3 голосов
/ 02 апреля 2009

Я создаю динамическое выражение, которое упорядочит элементы в списке по некоторому правилу (лямбда-эксп.). Это код:

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);

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

Ответы [ 4 ]

3 голосов
/ 21 мая 2009

упорядочить любое перечисляемое свойство (без отражения):

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);
        }
2 голосов
/ 06 апреля 2009

Это рабочий код:

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. Убедитесь, что вы используете один и тот же экземпляр выражения параметра ('list') при создании MethodCallExpression и LambdaExpression, а не два отдельных экземпляра даже с одним и тем же именем, в противном случае вы получите: "Лямбда-параметр не в области видимости" исключение без особых объяснений.

спасибо экспертам

1 голос
/ 16 сентября 2010

У меня была почти такая же проблема с 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
0 голосов
/ 02 апреля 2009

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

data.AsQueryable().OrderBy(exp);

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...