无法使用泛型lambda表达式执行LINQ Where子句

本文关键字:执行 LINQ Where 子句 表达式 lambda 泛型 | 更新日期: 2023-09-27 18:19:33

我正在尝试开发一个通用函数,该函数应用Where子句,但"inputQuery.Where(condition)"语句不编译。我得到"参数2:无法从"System.Linq.Expressions.LambdaExpression"转换为"System.Linq.Expressions.Expression<System.Func<object,bool>>"。

   public IQueryable<Object> ExecuteWhereClause(IQueryable<Object> inputQuery, Object typedValue, Type viewType, String paramName, Type paramType)
    {           
        ParameterExpression parameter = Expression.Parameter(viewType);
        Type[] typeArgs = { viewType, typeof(bool) };
        var condition =
             Expression.Lambda(
                 typeof(Func<,>).MakeGenericType(typeArgs),
                 Expression.Equal(
                     Expression.Property(parameter, paramName),
                     Expression.Constant(typedValue, paramType)
                 ),
                 parameter
             );
        return inputQuery.Where(condition);
    }

无法使用泛型lambda表达式执行LINQ Where子句

我想您有点混淆了表达式如何与Where一起工作。

Where函数中的谓词参数具有具体类型

Expression<Func<TSource, bool>> predicate

其中TSource-冷却中元素的类型,在您的情况下,您有集合IQueryable<Object> inputQuery,因此TSource始终是Object

返回值为静态类型-bool

所以,即使您以某种方式将通用LambdaExpression转换为Expression<Func<Object, bool>>,也会出现错误,因为viewType可能不是Object

这个问题你只需创建类型化的LambdaExpression 就可以解决

var condition =
    Expression.Lambda<Func<object,bool>>(
        Expression.Equal(
            Expression.Property(parameter, paramName),
            Expression.Constant(typedValue, paramType)
        ),
        parameter
    );

但现在如果viewType不是Object ,则会出现另一个错误

"类型的ParameterExpression不能用于"System.Object"类型的委托参数

因此,您有几种方法:
首先:不使用viewType,而是始终使用object,在这种情况下,当尝试获取属性时会出现另一个错误,因为您只能获取那些具有object类的属性。

第二:稍微改变一下你的函数,使用通用参数

IQueryable<Object>->IQueryable<T>

用这个T 创建参数

ParameterExpression parameter = Expression.Parameter(typeof(T));

因为您只能将此类型的参数传递给可用的Where函数lambda Expression.Lambda<Func<T,bool>>

使用Expression.Lambda<Func<T,bool>>-所以这确实需要Where-函数来处理源集合中元素类型的可用对象。

所以最后你们可以得到下一个功能:

public static IQueryable<T> ExecuteWhereClause<T>(IQueryable<T> inputQuery, object typedValue, String paramName)
{
    ParameterExpression parameter = Expression.Parameter(typeof(T));
    var condition =
            Expression.Lambda<Func<T,bool>>(
                Expression.Equal(
                    Expression.Property(parameter, paramName),
                    Expression.Constant(typedValue)
                ),
                parameter
            );
    return inputQuery.Where(condition);
}

甚至

public static IQueryable<T> ExecuteWhereClause<T,U>(IQueryable<T> inputQuery, U typedValue, String paramName)
{
    ParameterExpression parameter = Expression.Parameter(typeof(T));
    var condition =
            Expression.Lambda<Func<T,bool>>(
                Expression.Equal(
                    Expression.Property(parameter, paramName),
                    Expression.Constant(typedValue)
                ),
                parameter
            );
    return inputQuery.Where(condition);
}

您正在构建lambda,它需要viewType,但不能与Object一起使用。如果你想这样做,你必须投

public IQueryable<Object> ExecuteWhereClause(IQueryable<Object> inputQuery, Object typedValue, Type viewType, String paramName, Type paramType)
{
    ParameterExpression parameter = Expression.Parameter(typeof(Object));
    var condition =
         Expression.Lambda<Func<Object, bool>>(
             Expression.Equal(
                 Expression.Property(Expression.Convert(parameter, viewType), paramName),
                 Expression.Constant(typedValue, paramType)
             ),
             parameter
         );
    return inputQuery.Where(condition);
}