linq - 执行 LambdaExpression 的问题

标签 linq expression-trees

H.我正在尝试构建 linq 查询,该查询动态生成针对动态发送字段的自定义排序的查询。

我是

的构造逻辑
Expression<Func<string, int>> SpaceStringSortExpression = (a) => a.StartsWith(" ") ? 2 : 1; 

此代码 (SpaceStringSortExpression.ToString()) 的签名是 "a => IIF(a.StartsWith(\"\"), 2, 1)"

为了动态地做到这一点,我做了:

ParameterExpression parameter = Expression.Parameter(typeof(TSource), "p1");
            Expression orderByProperty = Expression.Property(parameter, propertyName);
            ConstantExpression c = Expression.Constant(" ", typeof(string));
            MethodInfo mi = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
            Expression call = Expression.Call(orderByProperty, mi, c);
            Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(call, parameter);
            ConditionalExpression t = Expression.IfThenElse(call, Expression.Constant(2), Expression.Constant(1));
            //t.tostring() - IIF(p1.Login.StartsWith(" "), 2, 1)
            LambdaExpression callt = Expression.Lambda(t, new[] { parameter });
            //callt.tostring() = p1 => IIF(p1.Login.StartsWith(" "), 2, 1)

但我无法将结果传递给 OrderBy

方法信息通用方法;

            genericMethod = OrderByMethod.MakeGenericMethod

            genericMethod = OrderByDescendingMethod.MakeGenericMethod
           (new[] { typeof(TSource), typeof(Int32) });

        object ret = genericMethod.Invoke(null, new object[] { source, callt });
        return (IQueryable<TSource>)ret;

我有(翻译自本地化 IIS)

Unable to convert "System.Linq.Expressions.Expression`1[System.Action`1[XXXX.User]]" to type "System.Linq.Expressions.Expression`1[System.Func`2[XXXX.User,System.Int32]]".

整个代码是:

public static IQueryable<TSource> OrderByPropertyRegardingWhiteSpaces<TSource>
        (this IQueryable<TSource> source, string propertyName, bool ascDirection = true)
        {
  ParameterExpression parameter = Expression.Parameter(typeof(TSource), "p1");
            Expression orderByProperty = Expression.Property(parameter, propertyName);
            ConstantExpression c = Expression.Constant(" ", typeof(string));
            MethodInfo mi = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
            Expression call = Expression.Call(orderByProperty, mi, c);
            Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(call, parameter);
            ConditionalExpression t = Expression.IfThenElse(call, Expression.Constant(2), Expression.Constant(1));
            //t.tostring() - IIF(p1.Login.StartsWith(" "), 2, 1)
            LambdaExpression callt = Expression.Lambda(t, new[] { parameter });
            //callt.tostring() = p1 => IIF(p1.Login.StartsWith(" "), 2, 1)
MethodInfo genericMethod;
genericMethod = OrderByMethod.MakeGenericMethod
                (new[] { typeof(TSource), typeof(Int32) });
object ret = genericMethod.Invoke(null, new object[] { source, callt });
            return (IQueryable<TSource>)ret;
   }



        private static readonly MethodInfo OrderByMethod =
        typeof(Queryable).GetMethods()
            .Where(method => method.Name == "OrderBy")
            .Where(method => method.GetParameters().Length == 2)
            .Single();

谁能帮我解决这个问题?

更简单的示例(仅按动态参数排序)工作正常:

public static IQueryable<TSource> OrderByProperty<TSource>
        (this IQueryable<TSource> source, string propertyName, bool ascDirection = true)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(TSource), "p1");
            Expression orderByProperty = Expression.Property(parameter, propertyName);

            LambdaExpression call = Expression.Lambda(orderByProperty, new[] { parameter });
MethodInfo genericMethod;
            if (ascDirection)
            {
                genericMethod = OrderByMethod.MakeGenericMethod
                (new[] { typeof(TSource), orderByProperty.Type });
            }
            else
            {
                genericMethod = OrderByDescendingMethod.MakeGenericMethod
               (new[] { typeof(TSource), orderByProperty.Type });
            }
            object ret = genericMethod.Invoke(null, new object[] { source, call });
            return (IQueryable<TSource>)ret;
        }

最佳答案

问题在于:

ConditionalExpression t = Expression.IfThenElse(call, Expression.Constant(2), Expression.Constant(1));

成为 Action 类型的表达式,执行“then”和“else”的表达式,但不会按预期返回值。这与 OrderBy 方法所需的签名不匹配,因此它会抛出您看到的异常。你想要这个:

ConditionalExpression t = Expression.Condition(call, Expression.Constant(2), Expression.Constant(1));

Condition 节点类型有一个返回值。调试它的一个好方法是编写一个执行此操作的单元测试:

Expression<Func<bool,int>> expr = (a) => a ? 2 : 1

然后使用调试器检查生成的表达式树。希望对您有所帮助。

关于linq - 执行 LambdaExpression 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8416327/

相关文章:

c# - 创建简单数学公式的表达式

c# - 假人的表达树?

c# - 如何针对集合调用 Expression<Func<Entity, bool>>

c# - 何时何地使用表达式树

c# - 动态 LINQ(到对象): Substituting a object name in a query from a list of object names (string)?

c# - 带输出参数的 Lambda 泛型表达式

c# - LINQ - 在 "a"和 "e"之间

c# - LINQ 转换函数

c# - 表达式列表 <Func<T, TProperty>>

c# - 如何从 lambda 表达式获取值?