LINQ:点表示法与查询表达式

60

我开始使用LINQ(目前是toXML和toSQL)。我发现有时候有两种或更多的方法可以达到相同的结果。以这个简单的例子为例,据我所知,它们都返回完全相同的内容:

SomeDataContext dc = new SomeDataContext();

var queue = from q in dc.SomeTable
        where q.SomeDate <= DateTime.Now && q.Locked != true
        orderby (q.Priority, q.TimeCreated)
        select q;

var queue2 = dc.SomeTable
        .Where( q => q.SomeDate <= DateTime.Now && q.Locked != true )
        .OrderBy(q => q.Priority)
        .ThenBy(q => q.TimeCreated);

这个想法是有两种表达同一件事的方法;我知道第一种方法有一些局限性,而且“点符号”更完整,但除此之外,还有其他优点吗?


感谢大家的回复。可惜我只能选一个作为正确答案。但我很感激所有的评论。 - Martin Marconcini
1
重复:https://dev59.com/YnVC5IYBdhLWcg3wrDRd - Mikhail Poda
5个回答

60

“点”符号通常称为Lambda语法。第一种符号有许多名称,但我通常将其称为查询语法。

我在一个由10名开发人员组成的团队中工作,我们长时间争论应该使用哪种语法作为标准。通常,经验更丰富(对于LINQ)的开发人员倾向于使用Lambda语法,但也存在重要的例外情况。

Lambda更加简洁,但是执行多个表连接就会变得非常困难。使用查询语法进行连接会更加清晰明了。反过来,有许多LINQ操作仅存在于Lambda语法中:Single()、First()、Count()等。

因此,使用您最舒适的语法,并意识到随着您的经验增长,您的偏好可能会改变。能够阅读两种语法具有很大的价值,在某些情况下,您必须同时使用它们。其他情况则更适合使用其中一种样式。最终,所有内容都会被转换为相同的可执行代码。


2
五年后,方法链式lambda语法现在通常被称为流畅接口 - Nick
3
4年后,微软似乎区分查询语法和方法语法:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq - Chris
1
9年过去了,我已经有7年没有进行.NET编程了。但是2010年这个答案非常好,即使今天也是如此。谢谢andleer :) - Martin Marconcini
@MartinMarconcini 很高兴能够帮忙。-Andrew Robinson - andleer
@andleer 我猜我应该在7-9年后回复,但以防万一(因为我变老了),未来的 再次感谢 - Martin Marconcini

29

我根据具体情况使用更易读的语法编写查询。

在可能的情况下,我尽量避免混合使用两种语法,尽管 有时候 这样做是可以的(例如如果是在查询末尾仅调用一次 First())。由于延迟执行,使用查询表达式并将结果分配给变量,然后 使用 该变量进行点符号表示法同样有效:

var query = from x in y
            orderby z
            group x by x.Name into groups
            // etc
            select foo;

var page = query.Skip(50).Take(10);

正如其他人所说的,查询表达式只是被转换成不带查询表达式的普通C# 3,因此这样做没有任何惩罚。


3
在需要同时使用两个变量时,再次为它们分离赋值可以获得额外的加分。这比将第一个变量用括号括起来,然后把剩下的内容添加到末尾更方便。 - Shibumi

8

嗯,'点'符号可以更短。例如:

var result = from p in dc.Products
             where p.Id > 5
             select p;

或者:

var result = dc.Products.Where(p => p.Id > 5);

我更喜欢后者,因为它更短、更易读。


在使用LINQ to SQL时,我更喜欢前者,因为它更接近T-SQL(在编写数据库查询时非常方便),而后者则适用于其他LINQ查询(如LINQ to XML)。 - RobS
是的,你说得对。使用linq2sql时,我经常使用第一种版本,出于你提到的同样的原因。虽然我也必须承认,对于像上面那个非常简单的查询,我经常使用第二个短版本,只是因为我懒 :-) - Razzie
它并不总是更短,有时阅读起来也更困难,但你说得对,它可以更简洁一些。 - Meta-Knight
当然,你是对的。但是如果你注意到我的第一句话,我说它可以更短 :-) 但是,从我的经验和像安德鲁所说的那样,有时候它会变得很长,几乎无法阅读,例如在连接的情况下。 - Razzie

3
我认为Lambda符号更加简洁优雅。但是我发现,如果你在方法调用中的任何地方使用Lambda表达式,你将无法在调试模式下即时修改代码,这让人感到很烦恼...

@MichaelFreidgeim - 不是的。:-) 自从写下这个答案以来,我发现了许多东西。 - Shaul Behr

2

它们编译成相同的代码,或者更准确地说,第一个版本首先被翻译成第二个版本,然后再进行编译。

你是正确的,第一个版本更加简洁但是功能更加有限。在第二个版本中,你可以使用已经存在的委托,例如:

Func<int, bool> isEven = i => i%2 == 0;
Enumerable.Range(10).Where(isEven).ToList().ForEach(Console.WriteLine);

并不完全正确。你仍然可以使用一个已经存在的委托,例如: var result = from s in list where isEven.Invoke(s.Length) select s; - Razzie
1
你不需要使用Invoke,这个代码可以正常工作: var result = from i in ints where isEven(i) select i; - theburningmonk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接