Reputation: 11079
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?
Upvotes: 3
Views: 3265
Reputation: 11
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
Upvotes: 1
Reputation:
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);
}
Upvotes: 3
Reputation: 11079
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);
thanks experts
Upvotes: 2
Reputation: 1503290
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 :)
Upvotes: 0