将Func传递给Where更改返回类型从IQueryable到IEnumerable

时间:2014-07-09 11:16:56

标签: c# linq lambda

我有以下代码;

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会影响类型推断。

1 个答案:

答案 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;表达并正确翻译。