动态创建的表达式

时间:2009-04-02 16:24:27

标签: c# lambda

我正在创建一个动态表达式,它将按一些规则(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);

现在我想在特定数据上执行以前创建的表达式来对其进行排序,但由于一些奇怪的异常,例如“Lambda参数不在范围内”或“参数表达式无效”,它会失败。

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

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

有人可以帮我吗?

4 个答案:

答案 0 :(得分: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);
        }

答案 1 :(得分: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,您应该将其包装在lambda表达式中。
  2. 确保在创建MethodCallExpression和LambdaExpression时使用相同的参数表达式实例('list'),而不是使用相同名称的两个单独的实例,否则您将得到:“Lambda参数不在范围内”没有太多解释的例外。
  3. 感谢专家

答案 2 :(得分: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

答案 3 :(得分:0)

有什么特别的原因你不只是打电话:

data.AsQueryable().OrderBy(exp);

你甚至需要在这里使用IQueryable吗?我觉得我错过了一些大局。你真的要把它作为LINQ to SQL(或LINQ to Entities)的一部分来调用吗?如果它只是在LINQ to Objects中,你不能只使用data.OrderBy(exp)吗?

基本上,更多解释会有所帮助:)

相关问题