Linq查询语法和扩展方法
本文关键字:扩展 方法 语法 查询 Linq | 更新日期: 2023-09-27 18:11:28
我通常更喜欢扩展方法,因为我发现它们更容易阅读,但是在看到Erno对这个问题的回答后,我想知道只使用扩展方法的最小查询会是什么样子?
更一般地说,是否存在可以用一种形式创建而不能用另一种形式创建的查询,或者两种方式是相同的?
摘自ILSpy:
var minimum = (from p1 in differenceList
from p2 in differenceList
let distance = Math.Abs(p1.X - p2.X)
where !object.ReferenceEquals(p1, p2)
orderby distance
select new { Point1 = p1, Point2 = p2, Distance = distance }).First();
是(稍微清理一下)和注释
var minimum = differenceList
// The two from
.SelectMany(
p1 => differenceList,
(p1, p2) =>
new {
p1 = p1,
p2 = p2
})
// The let
.Select(q =>
new{
q = q,
distance = Math.Abs(q.p1.X - q.p2.X)
})
// The where
.Where(r => !object.ReferenceEquals(r.q.p1, r.q.p2))
// The orderby
.OrderBy(r => r.distance)
// The final select
.Select(r => new
{
Point1 = r.q.p1,
Point2 = r.q.p2,
Distance = r.distance
})
// The First
.First();
我必须说实话,我唯一不知道如何"手工"的是两个from
。我怀疑这是SelectMany
,但我至少要花30分钟才能破解它。如果你感兴趣,在ILSpy Options->Decompiler and deactivate "Decompile query expressions.
在查询表达式中你不能做任何没有查询表达式就不能做的事情-查询表达式只是被翻译成非查询表达式代码。有很多查询,不能写在查询表达式虽然…例如,使用Select
过载的任何内容,它也提供了索引:
var foo = bar.Select((value, index) => new { value, index });
…当然,还有许多查询表达式根本不支持的操作符(First
等)。
"最小"查询将对第二个from
子句使用SelectMany
,对let
子句使用Select
(引入一个新的透明标识符),对where
子句使用Where
,对select
子句使用Select
。
一些查询只能使用扩展方法语法编写(特别是有些查询语法不支持的扩展方法)。扩展方法语法支持查询语法所支持的一切,因为查询语法被编译成完全相同的扩展方法。
另一方面,查询语法在扩展方法语法(let
和某些join
)中有一些更详细的功能。
join
可以被SelectMany
和let
替换,Select
引入了一个匿名类型,该类型既包括查询中的实际变量,也包括let
子句中引入的变量。
一个简洁的扩展方法语法应该是这样的:
differenceList
.SelectMany(p1=>differencelist,(p1,p2) => new {Point1 = p1,Point2 = p2,
Distance=Math.Abs(q.p1.X - q.p2.X)})
.Where(e=>!object.ReferenceEquals(e.p1,e.p2))
.OrderBy(e=>e.Distance)
.First();
每个Linq表达式都可以使用扩展方法表示。编译器会把Linq翻译成它们。另一方面,并不是每个扩展方法都可以用Linq语法表示。