我通常更喜欢扩展方法,因为我们发现它们更容易阅读,但在看到Erno给this question的答案后,我想知道最小查询看起来如何只用扩展方法?
更一般地说,是否存在可以在一种形式中创建但不能在另一种形式中创建的查询,或者两种方法是否相同?
答案 0 :(得分:10)
取自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.
答案 1 :(得分:5)
在查询表达式中没有什么可以做的,没有查询表达式就无法完成 - 无论如何,查询表达式只是被翻译成非查询表达式代码。有很多查询无法在查询表达式中编写,但是......例如,使用Select
重载的任何东西都提供了索引:
var foo = bar.Select((value, index) => new { value, index });
...当然,根本不是查询表达式所支持的所有运算符(First
等)。
“最小”查询将SelectMany
用于第二个from
子句,Select
用于let
子句(引入新的透明标识符),{{1} Where
子句用于where
子句,Select
用于select
子句。
答案 2 :(得分:1)
某些查询只能使用扩展方法语法编写(特别是查询语法不支持的扩展方法)。扩展方法语法支持查询语法支持的所有内容,因为查询语法被编译为完全相同的扩展方法。
另一方面,查询语法有一些在扩展方法语法(let
和某些join
s)中更加冗长的功能。
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();
答案 3 :(得分:0)
每个Linq表达式都可以使用扩展方法表达。无论如何,编译器将Linq转换为它们。另一方面,并非每种扩展方法都可以用Linq语法表达。