Linq 执行LambdaExpression时遇到的问题

Linq 执行LambdaExpression时遇到的问题,linq,expression-trees,Linq,Expression Trees,我正在尝试构造linq查询,该查询动态地为动态发送字段的自定义排序生成查询 我是逻辑的建构者 Expression<Func<string, int>> SpaceStringSortExpression = (a) => a.StartsWith(" ") ? 2 : 1; 整个守则是: public static IQueryable<TSource> OrderByPropertyRegardingWhiteSpaces<TSource&

我正在尝试构造linq查询,该查询动态地为动态发送字段的自定义排序生成查询

我是逻辑的建构者

Expression<Func<string, int>> SpaceStringSortExpression = (a) => a.StartsWith(" ") ? 2 : 1; 
整个守则是:

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();
公共静态IQueryable OrderByPropertyRegardingWhiteSpaces
(此IQueryable源,字符串propertyName,bool ascDirection=true)
{
ParameterExpression参数=Expression.parameter(typeof(TSource),“p1”);
Expression orderByProperty=Expression.Property(参数,propertyName);
ConstantExpression c=表达式.常量(“,typeof(string));
MethodInfo mi=typeof(string).GetMethod(“StartsWith”,新类型[]{typeof(string)});
Expression call=Expression.call(orderByProperty,mi,c);
表达式lambda=Expression.lambda(调用,参数);
ConditionalExpression t=Expression.IfThenElse(调用,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)
方法信息一般方法;
genericMethod=OrderByMethod.MakeGenericMethod
(新[]{typeof(TSource),typeof(Int32)});
object ret=genericMethod.Invoke(null,新对象[]{source,callt});
返回(IQueryable)ret;
}
私有静态只读MethodInfo OrderByMethod=
typeof(可查询).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;
        }
公共静态IQueryable OrderByProperty
(此IQueryable源,字符串propertyName,bool ascDirection=true)
{
ParameterExpression参数=Expression.parameter(typeof(TSource),“p1”);
Expression orderByProperty=Expression.Property(参数,propertyName);
LambdaExpression call=Expression.Lambda(orderByProperty,new[]{parameter});
方法信息一般方法;
如果(ASC方向)
{
genericMethod=OrderByMethod.MakeGenericMethod
(新[]{typeof(TSource),orderByProperty.Type});
}
其他的
{
genericMethod=OrderByDescendingMethod.MakeGenericMethod
(新[]{typeof(TSource),orderByProperty.Type});
}
object ret=genericMethod.Invoke(null,新对象[]{source,call});
返回(IQueryable)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));
条件节点类型具有返回值。调试此功能的一个好方法是编写一个单元测试,该测试可执行以下操作:

Expression<Func<bool,int>> expr = (a) => a ? 2 : 1
表达式expr=(a)=>a?2 : 1
然后使用调试器检查生成的表达式树。希望有帮助

ConditionalExpression t = Expression.IfThenElse(call, Expression.Constant(2), Expression.Constant(1));
ConditionalExpression t = Expression.Condition(call, Expression.Constant(2), Expression.Constant(1));
Expression<Func<bool,int>> expr = (a) => a ? 2 : 1