我有以下代码;
IQueryable<MyClass> query = listOfObjects.Where(x => x.SomeProp == 1);
我将此传递给期望IQueryable的特定API的方法,这很好。
但是,我希望动态构建谓词,因此我使用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客户端对象模型)失败了,通用&#34;不支持指定的方法。&#34; 错误消息。
我不知道这是LINQ提供商在幕后的限制,但无论如何......我很想知道为什么将Func
拉到自己的变量中并将其传递给Where
会影响类型推断。
答案 0 :(得分:7)
IQueryable
正在使用表达式树来构建谓词。所以,而不是
Func<MyClass, bool> predicate = x => GetPredicate();
使用:
Expression<Func<MyClass, bool>> predicate = x => GetPredicate();
请记住:
使用IQueryable
时构建表达式树(表示集合上的操作(作为操作数和参数)的树)。为了将树转换为其他形式(让我们说sql查询,取决于LINQ proider),翻译者必须知道树中使用的所有操作数。看起来你正在服务的翻译人员IQueryable
不知道GetPredicate
函数做了什么(并且不知道如何将其转换为sql查询)所以抛出< strong>不支持例外。。
同样的事情是Func而不是Expression。 Func是谓词的编译版本(存储为委托) - 提供者不知道如何翻译代表。当使用Expression时,谓词存储为树,因此提供者可以在内部查看&#34;表达并正确翻译。