3

I'm creating a dynamic expression, which will order items in a list by some rule (lambda exp.). This is the code:

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

Now I want to execute previously created expression on specific data to sort it, but it fails because of some strange exceptions like "Lambda Parameter not in scope" or "Argument expression is not valid".

var data = new String[] { "asdasdasd", "asdads", "123", "xcvxcvs", "ASDSD" };
// one of attempts: doesn't work
var result = data.AsQueryable().Provider.CreateQuery<String>(orderByExp);

Can somebody help me with this?

Michael Myers
193k47 gold badges301 silver badges297 bronze badges
asked Apr 2, 2009 at 16:24

4 Answers 4

3

order any enumerable by a property(no reflection):

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);
 }
answered May 21, 2009 at 14:44
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, it's a good way. But in my situation I need sort/filter more than just by property name (my example just a simple case to explain the other problem). I need to execute a simple lambda like o => o.Users.Any(user => user.Type == 1). Except this your solution is ok. Get my +1:)
2

This is the working code:

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. To execute the MethodCallExpression you should wrap it in lambda expression.
  2. Be sure you use the same instance of parameter expression ('list'), when creating a MethodCallExpression and LambdaExpression, and not two separate instances even with the same name, otherwise you will get the: "Lambda Parameter not in scope" exception without much explanation.

thanks experts

answered Apr 5, 2009 at 21:12

Comments

1

I had the nearly the same problem working with Linq, i decided to write a extension function, and some of the ideas were taken from the answers of this question:

<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
John Saunders
162k26 gold badges252 silver badges403 bronze badges
answered Sep 15, 2010 at 20:59

Comments

0

Is there any particular reason you're not just calling:

data.AsQueryable().OrderBy(exp);

Do you even need to use IQueryable here? I get the feeling I'm missing some of the big picture. Are you actually going to be calling this as part of LINQ to SQL (or LINQ to Entities)? If it's just within LINQ to Objects, can't you just use data.OrderBy(exp)?

Basically, some more explanation would be helpful :)

answered Apr 2, 2009 at 16:46

6 Comments

The whole picture is next: I want to create some query (rules like order, where, may be else) on some data, which I don't have right now. But I know its type. This query will later be sent to some web service, which has the data and will run the query on it.
and forgot, this is a simple LINQ to Objects.
Okay, now I'm confused - if you're sending the query to a web service, it doesn't sound like it's really LINQ to Objects. What do you want to do the ordering - the web service, or the local process?
More correctly I want to send an expression (expression tree) to a web service, which will retrieve a data from DB, run my expression/query on that data and return the result data. I'm not sure all this called LINQ to Objects.
Okay. Aside from the fun you're going to have serializing the expression tree, I believe just using Queryable.OrderBy (as per my answer) should be okay. Have you tried it yet?
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.