正确的 LINQ 其中子句

我在日常生活中写了相当多的 LINQ,但大部分都是简单的陈述。我已经注意到,当使用 where子句时,有许多方法来写它们,而且就我所知,每种方法都有相同的结果。例如:

from x in Collection
where x.Age == 10
where x.Name == "Fido"
where x.Fat == true
select x;

至少就结果而言,似乎与此相当:

from x in Collection
where x.Age == 10 &&
x.Name == "Fido" &&
x.Fat == true
select x;

那么,除了语法之外,真的还有区别吗? 如果有,首选的样式是什么? 为什么?

332344 次浏览

第二个谓词会更有效率,因为它只有一个谓词来对集合中的每个项进行计算,与第一个谓词一样,它首先将第一个谓词应用于所有项,然后将结果(此时缩小了)用于第二个谓词,以此类推。每次传球结果都缩小了,但仍然涉及到多次传球。

另外,链接(第一种方法)只有在与谓词连接时才有效。类似这样的 x.Age == 10 || x.Fat == true将不能用于您的第一个方法。

第一个将实施:

Collection.Where(x => x.Age == 10)
.Where(x => x.Name == "Fido") // applied to the result of the previous
.Where(x => x.Fat == true)    // applied to the result of the previous

相对于简单得多(而且 快得多可能更快) :

// all in one fell swoop
Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true)

编辑: LINQtoObjects 的行为与我预期的不一样。你可能会对我刚才写的 博客文章感兴趣..。


它们在名称上有所不同——第一个等价于:

Collection.Where(x => x.Age == 10)
.Where(x => x.Name == "Fido")
.Where(x => x.Fat == true)

而后者相当于:

Collection.Where(x => x.Age == 10 &&
x.Name == "Fido" &&
x.Fat == true)

现在,事实上所产生的差异取决于被调用的 Where的实现。如果它是一个基于 SQL 的提供程序,我希望两者最终创建相同的 SQL。如果是在 LINQ to Objects 中,那么第二个迭代器的间接级别会更少(只涉及两个迭代器,而不是四个)。就速度而言,这些间接水平是否是 意义重大则是另一回事。

通常我会使用几个 where子句,如果他们觉得他们代表显着不同的条件(例如,一个是做一个对象的一部分,一个是完全独立的)和一个 where子句,当各种条件是密切相关的(例如,一个特定的值大于一个最小值,小于一个最大值)。基本上,在出现任何细微的性能差异之前,值得考虑可读性。

仔细看看,这两个语句将被转换为不同的查询表示。取决于 CollectionQueryProvider,这可能会被优化掉,也可能不会。

当这是一个 linq-to-object 调用时,多个 where 子句将导致相互读取的 IEnumerables 链。使用单子句形式将有助于此处的性能。

当底层提供程序将其转换为 SQL 语句时,两个变体很可能创建相同的语句。

当我奔跑的时候

from c in Customers
where c.CustomerID == 1
where c.CustomerID == 2
where c.CustomerID == 3
select c

还有

from c in Customers
where c.CustomerID == 1 &&
c.CustomerID == 2 &&
c.CustomerID == 3
select c customer table in linqpad

对我的 Customer 表输出相同的 sql 查询

-- Region Parameters
DECLARE @p0 Int = 1
DECLARE @p1 Int = 2
DECLARE @p2 Int = 3
-- EndRegion
SELECT [t0].[CustomerID], [t0].[CustomerName]
FROM [Customers] AS [t0]
WHERE ([t0].[CustomerID] = @p0) AND ([t0].[CustomerID] = @p1) AND ([t0].[CustomerID] = @p2)

所以在 sql 的转换中没有区别,你们已经在其他答案中看到它们是如何被转换成 lambda 表达式的