如何将Expression<Func<TSource,TKey>>与TKey转换为Expression<Func<TSource,bool>>?
IQueryable.OrderBy接收键选择器表达式Expression<Func<TSource,TKey>>,IQueryable.Single接收比较表达式Expression<Func<TSource,bool>>。
能否将Expression<Func<TSource,TKey>>与TKey值转换为Expression<Func<TSource,bool>>?例如,若有键选择器表达式x => e => e.Id,希望得到比较表达式x => e => e.Id == value。
我编写了如下方法:
public Expression<Func<TEntity, bool>> KeyComparator(TKey key) => Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(KeySelector, Expression.Constant(key)))
该方法可通过编译,我能编写someQueryable.Single(KeyComparator(key))这类代码,但运行时出现以下错误:
The binary operator Equal is not defined for the types 'System.Func`2[TSource,System.Int32]' and 'System.Int32'.
其中TSource是我的实际类名,这似乎表示int与int之间未定义相等比较?这是怎么回事?
错误原因
你直接把整个键选择器表达式KeySelector(类型为Expression<Func<TEntity, TKey>>)和常量值做相等比较,这相当于试图把委托类型和int类型做对比,自然会触发类型不匹配错误——不是int和int不能比较,是你拿Func类型和int做比较了。
解决方法
需要提取键选择器表达式里的主体返回部分(比如e => e.Id里的e.Id节点),再和常量值构建相等比较逻辑,最后重新生成Lambda表达式。
修改后的代码如下:
public Expression<Func<TEntity, bool>> KeyComparator(TKey key) { // 获取键选择器的主体表达式(比如e.Id) var keyBody = KeySelector.Body; // 创建带明确类型的常量表达式 var constant = Expression.Constant(key, typeof(TKey)); // 构建相等比较表达式 var equalExpr = Expression.Equal(keyBody, constant); // 复用原键选择器的参数,生成新的Lambda表达式 return Expression.Lambda<Func<TEntity, bool>>(equalExpr, KeySelector.Parameters); }
补充说明
KeySelector.Body会提取键选择器里的返回值节点,比如对于e => e.Id,Body就是代表e.Id的MemberExpression。- 显式指定
Expression.Constant的类型,避免值类型装箱引发的潜在问题。 - 复用原键选择器的参数,确保新Lambda的参数能正确绑定到
TEntity实例,保证表达式树逻辑的正确性。
内容的提问来源于stack exchange,提问作者Kevin Krumwiede

