Fluent 和 Query Expression — 两者相比有啥好处吗?

Posted

技术标签:

【中文标题】Fluent 和 Query Expression — 两者相比有啥好处吗?【英文标题】:Fluent and Query Expression — Is there any benefit(s) of one over other?Fluent 和 Query Expression — 两者相比有什么好处吗? 【发布时间】:2010-09-17 21:19:18 【问题描述】:

LINQ 是自泛型以来对 .NET 的最大改进之一,它为我节省了大量时间和代码行数。但是,流畅的语法对我来说似乎比查询表达式语法更自然。

var title = entries.Where(e => e.Approved)
    .OrderBy(e => e.Rating).Select(e => e.Title)
    .FirstOrDefault();

var query = (from e in entries
             where e.Approved
             orderby e.Rating
             select e.Title).FirstOrDefault();

两者之间有什么区别吗?或者两者之间有什么特别的好处?

【问题讨论】:

对于复杂的查询,我发现 lambda 语法更易于理解/可读,但查询语法更漂亮。 【参考方案1】:

两者都不是更好:它们满足不同的需求。当您想利用多个范围变量时,查询语法就会发挥作用。这在三种情况下会发生:

使用 let 关键字时 当您有多个生成器时(from 子句) 连接时

这是一个示例(来自 LINQPad 示例):

string[] fullNames =  "Anne Williams", "John Fred Smith", "Sue Green" ;

var query =
  from fullName in fullNames
  from name in fullName.Split()
  orderby fullName, name
  select name + " came from " + fullName;

现在将其与方法语法中的相同内容进行比较:

var query = fullNames
  .SelectMany (fName => fName.Split().Select (name => new  name, fName  ))
  .OrderBy (x => x.fName)
  .ThenBy  (x => x.name)
  .Select  (x => x.name + " came from " + x.fName);

另一方面,方法语法公开了查询运算符的全部范围,并且对于简单查询更加简洁。您可以通过混合查询和方法语法来获得两全其美的效果。这通常在 LINQ to SQL 查询中完成:

var query =
  from c in db.Customers
  let totalSpend = c.Purchases.Sum (p => p.Price)    // Method syntax here
  where totalSpend > 1000
  from p in c.Purchases
  select new  p.Description, totalSpend, c.Address.State ;

【讨论】:

不错的答案。你能告诉我更多关于“.Select (name => new name, fName )”在做什么吗? 它以匿名类型选择单个单词(anne、williams、john 等)以及全名。这允许您“携带”原始全名,以便您可以在查询的其余部分访问全名和单个单词。【参考方案2】:

当我可以用这种方式编写整个表达式时,我更喜欢使用后者(有时称为“查询理解语法”)。

var titlesQuery = from e in entries
                  where e.Approved
                  orderby e.Rating
                  select e.Titles;

var title = titlesQuery.FirstOrDefault();

只要我必须添加(括号)和.MethodCalls(),我就会改变。

当我使用前者时,我通常每行放一个子句,如下所示:

var title = entries
    .Where (e => e.Approved)
    .OrderBy (e => e.Rating)
    .Select (e => e.Title)
    .FirstOrDefault();

我觉得这更容易阅读。

【讨论】:

【参考方案3】:

每种风格都有其优点和缺点。查询语法在连接方面更好,它具有有用的 let 关键字,可以轻松在查询中创建临时变量。

另一方面,Fluent 语法有更多的方法和操作没有通过查询语法公开。此外,由于它们只是扩展方法,您可以编写自己的方法。

我发现,每次我开始使用查询语法编写 LINQ 语句时,我最终都不得不将它放在括号中,然后转而使用流畅的 LINQ 扩展方法。查询语法本身没有足够的功能来使用。

【讨论】:

"因为它们只是扩展方法,你可以自己编写。" ——你会遇到这个问题吗? ***.com/a/3850254/1175496【参考方案4】:

VB.NET 中我非常喜欢查询语法。

我讨厌重复丑陋的Function-keyword:

Dim fullNames =  "Anne Williams", "John Fred Smith", "Sue Green" ;
Dim query =
     fullNames.SelectMany(Function(fName) fName.Split().
     Select(Function(Name) New With Name, fName)).
     OrderBy(Function(x) x.fName).
     ThenBy(Function(x) x.Name).
     Select(Function(x) x.Name & " came from " & x.fName)

在我看来,这个简洁的查询更具可读性和可维护性:

query = From fullName In fullNames
        From name In fullName.Split()
        Order By fullName, name
        Select name & " came from " & fullName

VB.NET 的查询语法也比 C# 更强大,更简洁:https://***.com/a/6515130/284240

例如这个 LINQ to DataSet(Objects) 查询

VB.NET:

Dim first10Rows = From r In dataTable1 Take 10

C#:

var first10Rows = (from r in dataTable1.AsEnumerable() 
                   select r)
                   .Take(10);

【讨论】:

对那些不能使用查询样式的VB开发者表示同情。 您的最后一个 C# 示例过于简单而没有价值:您只需编写 `dataTable1.AsEnumerable().Take(10); @Emyr:我最后一段以“VB.NET 的查询语法也比 C# 更强大、更简洁”开头的段落只是将 VB.NET 的查询语法与 C# 进行比较,您使用的是方法语法.【参考方案5】:

我根本没有得到查询语法。在我的脑海里没有任何理由。 let 可以通过 .Select 和匿名类型来实现。我只是觉得里面的“标点符号”看起来更有条理。

【讨论】:

使用流畅的语法,多个连接会很快变得相当费力。不过,我自己通常会使用流利的 - 除非涉及连接。 @Instance Hunter:这里也一样。我花了很长时间才开始掌握流利语法的概念。结合强大的可枚举和“纯”函数的想法,我现在真的很喜欢它,以及以前没有很好的代码表示的棘手情况。对于ye-ole-SQL-part的大脑来说,拥有查询语法仍然是一件幸事。【参考方案6】:

流畅的界面,如果只有一个地方。如果我需要 select 或 orderby,我通常使用 Query 语法。

【讨论】:

【参考方案7】:

Fluent 语法确实看起来更强大,它也应该更适合将代码组织成小的可重用方法。

【讨论】:

【参考方案8】:

我知道这个问题是用 C# 标记的,但是 VB.NET 的 Fluent 语法非常冗长。

【讨论】:

【参考方案9】:

我真的很喜欢 Fluent 语法,我尽量使用它,但在某些情况下,例如我使用连接的地方,我通常更喜欢 Query 语法,在这些情况下我发现它更容易阅读,而且我认为有些人比 lambdas 更熟悉 Query(类 SQL)语法。

【讨论】:

【参考方案10】:

虽然我理解并喜欢 fluent format ,但出于可读性原因,我暂时坚持使用 Query。刚接触 LINQ 的人会发现 Query 读起来更舒服。

【讨论】:

【参考方案11】:

我更喜欢查询语法,因为我来自使用 SQL 的传统 Web 编程。对我来说,把头绕起来要容易得多。但是,它认为我会开始使用 .Where(lambda),因为它肯定要短得多。

【讨论】:

【参考方案12】:

我已经使用 Linq 大约 6 个月了。当我第一次开始使用它时,我更喜欢它的查询语法,因为它与 T-SQL 非常相似。

但是,我现在逐渐转向前者,因为将可重用的代码块编写为扩展方法并将它们链接在一起很容易。虽然我确实发现将每个子句放在自己的行上有助于提高可读性。

【讨论】:

【参考方案13】:

我刚刚建立了我们公司的标准,我们强制使用扩展方法。我认为选择一个而不是另一个是个好主意,不要在代码中混淆它们。扩展方法读起来更像其他代码。

理解语法没有所有运算符,在查询周围使用括号并添加扩展方法毕竟只是求我从一开始就使用扩展方法。

但在大多数情况下,这只是个人喜好,也有少数例外。

【讨论】:

我不会强制执行个人喜好.. 但那就是我。【参考方案14】:

来自微软的文档:

作为一个规则,当您编写 LINQ 查询时,我们建议您尽可能使用查询语法,并在必要时使用方法语法。两种不同形式之间没有语义或性能差异。查询表达式通常比用方法语法编写的等效表达式更具可读性。

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/#query-expression-overview

他们还说:

要开始使用 LINQ,您不必广泛使用 lambda。 但是,某些查询只能用方法语法表示,其中一些需要 lambda 表达式

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq

【讨论】:

以上是关于Fluent 和 Query Expression — 两者相比有啥好处吗?的主要内容,如果未能解决你的问题,请参考以下文章

Fluent验证扩展方法

LINQ Fluent NHIBERNATE .Contains() 在 QueryOver<> 中不起作用,但在 Query<> 中起作用

Media query expression must begin with '(' 错误

codeception 中的 fillField 方法不起作用抛出 DOMXPath::query(): Invalid expression

在 Vapor 命令中使用 Fluent

mysql:In aggregated query without GROUP BY, expression #1 of SELECT list contains...........