将函数传递给Where将返回类型从IQueryable改为IEnumerable
本文关键字:IQueryable 改为 IEnumerable 返回类型 Where 函数 | 更新日期: 2023-09-27 18:12:12
我有以下代码;
IQueryable<MyClass> query = listOfObjects.Where(x => x.SomeProp == 1);
我将此传递给特定API上的一个方法,该方法需要一个IQueryable,这很好。
然而,我想动态地建立谓词,所以我使用Expression.Lambda
来实现这一点,然后我用.Compile
把它变成一个Func<MyObject, bool>
。
我原以为下面的语句是正确的;
Func<MyClass, bool> predicate = x => GetPredicate();
IQueryable<MyClass> query = list.Fields.Where(predicate);
然而,将predicate
传递给Where
已经将返回类型更改为IEnumerable<MyClass>
,这显然不是API所要求的类型。
我确实(天真地)尝试predicate.AsQueryable()
,但有问题的API (SharePoint客户端对象模型)只是失败与一个通用的"指定的方法是不支持的。"错误消息。
我不知道这是否是LINQ提供程序的限制,但无论如何…我很想了解为什么将Func
拉出到自己的变量中并将其传递给Where
会影响类型推断。
IQueryable
使用表达式树构建谓词。所以,不用
Func<MyClass, bool> predicate = x => GetPredicate();
使用:
Expression<Func<MyClass, bool>> predicate = x => GetPredicate();
请记住:在使用IQueryable
时,构建了表达式树(表示对集合进行的操作(作为操作数和参数)的树)。为了将树转换成其他形式(比如sql查询,取决于LINQ提供程序),翻译人员必须知道树中使用的所有操作数。它看起来像服务中的翻译器,你传递IQueryable
不知道GetPredicate
函数做什么(也不知道如何将其转换为sql查询),所以抛出不支持异常。
用Func代替Expression也是一样。Func是谓词的编译版本(存储为委托)-提供程序不知道如何转换委托。当使用Expression时,谓词被存储为树,因此提供者可以"查看"表达式并正确翻译它。