Linq查询语法和扩展方法
我通常更喜欢扩展方法,因为他们发现它们更容易阅读,但在看到Erno对这个问题的答案之后,我想知道最小查询如何只使用扩展方法?
更一般地说,是否存在可以在一种forms而不是另一种forms中创建的查询,或者两种方法是否相同?
在查询表达式中没有什么可以做的,没有查询表达式就无法完成 – 无论如何,查询表达式只是被翻译成非查询表达式代码。 有很多查询无法在查询表达式中编写,但是…例如,使用Select
过载的任何东西都提供了索引:
var foo = bar.Select((value, index) => new { value, index });
…当然,所有许多运算符根本不受查询表达式的支持( First
etc)。
“最小”查询将使用SelectMany
用于第二个from
子句, Select
用于let
子句(引入新的透明标识符), Where
用于where
子句, Select
用于select
子句。
来自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(rqp1, rqp2)) // The orderby .OrderBy(r => r.distance) // The final select .Select(r => new { Point1 = rqp1, Point2 = rqp2, Distance = r.distance }) // The First .First();
我必须说实话,我唯一不知道怎么做“手工”的是两个from
。 我怀疑它是一个SelectMany
,但它至少花了我30分钟来破解它。 如果您有兴趣,请在ILSpy Options->Decompiler and deactivate "Decompile query expressions.
某些查询只能使用扩展方法语法编写(特别是查询语法不支持的扩展方法)。 扩展方法语法支持查询语法支持的所有内容,因为查询语法被编译为完全相同的扩展方法。
另一方面,查询语法具有一些在扩展方法语法( let
和某些join
s)中更加冗长的特性。
join
可以由SelectMany
替换,并使用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语法表示。