分配谓词变量而不是 lambda 表达式

Posted

技术标签:

【中文标题】分配谓词变量而不是 lambda 表达式【英文标题】:Assigning a predicate variable instead of a lambda expression 【发布时间】:2021-12-20 05:05:34 【问题描述】:

以下教科书 Join 查询运行良好:

var list = from family in db.Families.Where(f => !f.isDeleted)
  join member in db.Members.Where(m => !m.isDeleted)
  on family.Id equals member.FamilyID
  select new  family = family.LastName, member = member.DisplayName ;

listIQueryable: Microsoft.FrameworkCore.Query.Internal.EntityQueryable<<>f__AnonymousType0<string, string>>,我可以打电话给list.ToList()

但是,如果我在第一个 Where 中使用谓词,而不是使用 lambda,如下所示:

Predicate<Family> query = f => !f.isDeleted;
var list = from family in db.Families.Where(new Func<Family, bool>(query))
  join member in db.Members.Where(m => !m.isDeleted)
  on family.Id equals member.FamilyID
  select new  family = family.LastName, member = member.DisplayName ;

然后list 变为[IEnumerable]: System.Linq.Enumerable.&lt;JoinIterator&gt;d__105&lt;Family, Member, short, &lt;&gt;f__AnonymousType0&lt;string, string&gt;&gt;,结果视图抛出“已经有一个打开的 DataReader 与此连接关联,必须先关闭。”。

我无法再重现它,但我确信有时结果视图会引发“数据为空”异常。

我需要使我的过滤器成为一个变量,因为所需的确切过滤器取决于其他一些条件。为什么使用Predicate 赋值会导致list 的类型不同,我该如何解决这个错误?

【问题讨论】:

您正在调用 Where 的不同重载。你应该在那里传递Expression&lt;Func&lt;Family, bool&gt;&gt;,而不是Func&lt;Family, bool&gt; 我该怎么做?我将query 更改为Expression&lt;Predicate&lt;Family&gt;&gt; query = f =&gt; !f.isDeleted;,但无法将其放入.Where(query) 请再次阅读我的评论。我没说Expression&lt;Predicate&lt;Family&gt;&gt; 谢谢。现在可以了。我理解错了Predicate&lt;T&gt;Func&lt;T, bool&gt; 一样。 它在概念上是相同的,但它们仍然是不同类型的委托,即使它们具有相同的签名。而 Where 则特别期望 Func。 【参考方案1】:

您正在调用Where 的两个非常不同的重载。在第一个代码 sn-p 中,您正在调用:

Where&lt;TSource&gt;(IQueryable&lt;TSource&gt;, Expression&lt;Func&lt;TSource,Boolean&gt;&gt;)

此重载将您的 lambda 表达式转换为 SQL 查询并在数据库上运行。

在第二个代码 sn-p 中,您正在调用

Where&lt;TSource&gt;(IEnumerable&lt;TSource&gt;, Func&lt;TSource,Boolean&gt;)

第二个重载是 LINQ to Objects Where,它根本不知道您的数据库。它适用于所有IEnumerable&lt;T&gt;s。

您应该创建一个Expression&lt;Func&lt;Family, bool&gt;&gt; 并将其传入:

Expression<Func<Family, bool>> query = f => !f.isDeleted;
var list = from family in db.Families.Where(query)
    ...

【讨论】:

以上是关于分配谓词变量而不是 lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章

如何检查是不是未分配 lambda 表达式? [复制]

c++基础(lambda)

函数式编程那些事儿

调用 lambda 表达式而不将其分配给委托

匿名函数lambda

lambda表达式和for_each