Linq查询语法和扩展方法

本文关键字:扩展 方法 语法 查询 Linq | 更新日期: 2023-09-27 18:11:28

我通常更喜欢扩展方法,因为我发现它们更容易阅读,但是在看到Erno对这个问题的回答后,我想知道只使用扩展方法的最小查询会是什么样子?

更一般地说,是否存在可以用一种形式创建而不能用另一种形式创建的查询,或者两种方式是相同的?

Linq查询语法和扩展方法

摘自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可以被SelectManylet替换,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语法表示。