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

Chr*_*ney 3 c# linq lambda

我有以下代码;

IQueryable<MyClass> query = listOfObjects.Where(x => x.SomeProp == 1);
Run Code Online (Sandbox Code Playgroud)

我将此传递给一个特定API的方法,该方法期望IQueryable,这很好.

但是,我想动态构建谓词,所以我正在使用它Expression.Lambda来实现这一点,然后我.Compile将它转回一个Func<MyObject, bool>.

我原以为以下会有效;

Func<MyClass, bool> predicate = x => GetPredicate();
IQueryable<MyClass> query = list.Fields.Where(predicate);
Run Code Online (Sandbox Code Playgroud)

但是,传递predicateWhere已经将返回类型更改为IEnumerable<MyClass>,这显然不是API所需的类型.

我做了(天真地)尝试predicate.AsQueryable(),但有问题的API(SharePoint客户端对象模型)失败了,通用的"不支持指定的方法".错误信息.

我不知道这是LINQ提供程序的局限性,但是无论如何......我很想理解为什么将其Func拉出到自己的变量中并将其传入以Where影响类型推断的方式它确实.

小智 7

IQueryable正在使用表达式树来构建谓词.所以,而不是

Func<MyClass, bool> predicate = x => GetPredicate();
Run Code Online (Sandbox Code Playgroud)

使用:

Expression<Func<MyClass, bool>> predicate = x => GetPredicate();
Run Code Online (Sandbox Code Playgroud)

请记住:使用IQueryable表达式树时(树表示在集合上进行的操作(作为操作数和参数)).为了将树转换为其他形式(假设sql查询,取决于LINQ proider),转换器必须知道树中使用的所有操作数.看起来你正在传递的服务中的转换器IQueryable不知道GetPredicate函数做了什么(并且不知道如何将它转换为sql查询)所以抛出不支持的异常..

同样的事情是Func而不是Expression.Func是谓词的编译版本(存储为委托) - 提供者不知道如何翻译代理.使用Expression时,谓词将存储为树,因此提供程序可以"查看"表达式并正确转换它.