67

我正在尝试了解是否有时间使用标准 linq 关键字或带有 lambda 表达式的 linq 扩展方法。他们似乎做同样的事情,只是写法不同。纯粹是风格问题吗?

var query = from p in Products
    where p.Name.Contains("foo")
    orderby c.Name
    select p;

// or with extension methods:
var query = Products
    .Where(p => p.Name.Contains("foo"))
    .OrderBy(p => p.Name);

它们与第二个示例非常相似,更简洁一些,但如果您不知道 => 正在做什么,则表达能力可能会降低。

除了编写简洁的代码之外,与 LINQ 语法相比,使用扩展方法还有其他优点吗?

4

7 回答 7

36

老实说,一旦你开始使用 Funcs 和 Actions,有时它可能是情境性的。假设您正在使用这三个函数:

  Func<DataClasses.User, String> userName = user => user.UserName;
  Func<DataClasses.User, Boolean> userIDOverTen = user => user.UserID < 10;
  Func<DataClasses.User, Boolean> userIDUnderTen = user => user.UserID > 10;

如您所见,第一个替换了 lamdba 表达式以获取用户名,第二个替换了用于检查 ID 是否低于 10 的 lamdba 表达式,让我们面对现实吧,第三个现在应该很容易理解了。

注意:这是一个愚蠢的例子,但它有效。

  var userList = 
    from user in userList
    where userIDOverTen(user)
    select userName;

相对

  var otherList =
    userList
    .Where(IDIsBelowNumber)
    .Select(userName)

在这个例子中,第二个稍微不那么冗长,因为扩展方法可以充分利用 Func,但 Linq 表达式不能,因为它只查找布尔值而不是返回布尔值的 Func。但是,这可能是使用表达式语言更好的地方。假设您已经有了一个方法,它不仅可以接收用户:

  private Boolean IDIsBelowNumber(DataClasses.User user, 
          Int32 someNumber, Boolean doSomething)
  {
    return user.UserID < someNumber;
  }

注意: doSomething 之所以存在,是因为 where 扩展方法可以接受用户和整数并返回布尔值的方法。这个例子有点烦人。

现在,如果您查看 Linq 查询:

  var completeList =
     from user in userList
     where IDIsBelowNumber(user, 10, true)
     select userName;

你很适合它。现在扩展方法:

  var otherList =
    userList
    .Where(IDIsBelowNumber????)
    .Select(userName)

如果没有 lambda 表达式,我真的无法调用该方法。所以现在我要做的是创建一个基于原始方法调用创建 Func 的方法。

   private Func<DataClasses.User, Boolean> IDIsBelowNumberFunc(Int32 number)
   {
      return user => IDIsBelowNumber(user, number, true);
   }

然后将其插入:

  var otherList =
     userList
     .Where(IDIsBelowNumberFunc(10))
     .Select(userName)

所以你可以看到,有时使用查询方法可能更容易。

于 2008-11-12T15:32:47.717 回答
25

使用 LINQ 扩展方法(基于方法的查询)的一个优点是您可以定义自定义扩展方法并且它仍然可以正常读取。

另一方面,当使用 LINQ查询表达式时,自定义扩展方法不在关键字列表中。与其他关键字混合起来看起来有点奇怪。

例子

我正在使用一个名为的自定义扩展方法Into,它只需要一个字符串:

查询示例

var query = (from p in Products
    where p.Name.Contains("foo")
    orderby c.Name
    select p).Into("MyTable");

扩展方法示例

var query = Products
                   .Where(p => p.Name.Contains("foo"))
                   .OrderBy(p => p.Name)
                   .Into("MyTable");

在我看来,后者,使用基于方法的查询,当你有自定义扩展方法时,读起来会更好。

于 2008-11-11T01:16:14.577 回答
14

我认为最好不要一起使用它们并选择一个并坚持下去。

主要是个人喜好,但在查询语法(理解方法)中,并非所有运算符都像之前所说的那样可用。

我发现扩展方法语法更符合我的代码的其余部分。我在 SQL 中执行我的 SQL。只需使用扩展方法将所有内容相互叠加,即可轻松构建您的表达式。

只是我的两分钱。

由于我还不能发表评论,所以我想在这里对编程工具的答案发表评论:为什么要为最后一个示例制作一个全新的方法?你不能只使用:

.Where(user => IDIsBelowNumber(user, 10, true))

于 2010-12-01T07:09:13.587 回答
6

它们编译相同,并且是等效的。就个人而言,对于大多数事情,我更喜欢 lambda(扩展)方法,仅当我正在执行 LINQ to SQL 或以其他方式尝试模拟 SQL 时才使用语句(标准)。我发现 lambda 方法在代码中的流动性更好,而语句在视觉上会分散注意力。

于 2008-11-11T01:04:10.467 回答
4

当我使用没有等效查询语法的 Linq 方法时,我更喜欢扩展方法语法,例如 FirstOrDefault() 或其他类似方法。

于 2008-11-12T14:30:19.760 回答
-2

我喜欢在它真正是查询时使用查询语法,即按需评估的惰性表达式。

看起来像常规方法调用(方法语法或 lambda 语法)的方法看起来不够懒惰,所以我将其用作约定。例如,

var query = from p in Products
            where p.Name.Contains("foo")
            orderby p.Name
            select p;

var result = query.ToList(); //extension method syntax

如果不是查询,我喜欢流畅的风格,在我看来与其他急切执行的调用一致。

var nonQuery = Products.Where(p => p.Name.Contains("foo"))
                       .OrderBy(p => p.Name)
                       .ToList();

它帮助我更好地区分这两种调用方式。当然,在某些情况下,无论如何您都将被迫使用方法语法,因此我的约定不够引人注目。

于 2014-03-06T17:22:33.783 回答
-2

扩展方法/lynda 表达式的一个优点是提供了额外的运算符,例如 Skip 和 Take。例如,如果您正在创建分页方法,那么能够跳过前 10 条记录并获取接下来的 10 条记录很容易实现。

于 2018-01-09T16:35:12.663 回答