【问题标题】:How do "Where" and "Select" work in LINQ?“在哪里”和“选择”如何在 LINQ 中工作?
【发布时间】:2019-12-06 06:47:20
【问题描述】:

我有以下 sn-p 代码。我对后面提到的代码 sn-p 几乎没有疑问。

var salaries = customerList
                    .Where(c => c.Age > 30)
                    .Select(c => c.Salary) // salary is of type long
                    .ToList();
  • 在上面的sn-p代码中,“Where”如何访问customerList,又如何定义“c”的类型?
  • 在应用 Select 操作的过滤器后,“Where”是否会返回客户的临时列表?
  • “Select”究竟如何知道它必须只返回“Salary”?
  • 如何将变量“salaries”的类型设置为 List?

【问题讨论】:

标签: c# linq


【解决方案1】:

Where 可能是这样实现的(请注意,这是一个非常粗略的实现,只是让您了解一下它是什么样的):

public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
    foreach (T t in source) {
        if (predicate(t)) {
            yield return t;
        }
    }
}

注意Where 是一种扩展方法。您实际上是在调用Where(customerList, c =&gt; c.Age &gt; 30)。现在您应该看到它在哪里可以访问customerList。它还通过查看IEnumerable customerList 的类型来推断T 应该是什么。因为它是IEnumerable&lt;Customer&gt;,所以TCustomer,所以它期望Func&lt;Customer, bool&gt; 作为第二个参数。这就是它知道cCustomer 的方式。

Where 不返回临时列表。许多 LINQ 方法都使用延迟评估。 Where 返回经过过滤的 IEnumerable&lt;Customer&gt;。请记住,IEnumerable 只是一系列事情。但是,Where 返回的这个序列不会被评估,直到你要求它。 Select 也一样。因此,在您调用 ToList 之前不会创建列表。

您的第三个问题有点像问“Where 如何知道如何过滤”或“Console.WriteLine 如何知道如何在屏幕上写入”。这就是Select 所做的。如果需要,您可以查看它的实现。这是一个粗略的草图:

public static IEnumerable<U> Select<T, U>(this IEnumerable<T> source, Func<T, U> mapping) {
    foreach (T t in source) {
        yield mapping(t);
    }
}

变量salaries 的类型是通过查看您调用的每个方法的方法签名来确定的。你的Select 调用返回一个IEnumerable&lt;long&gt;ToList 的签名告诉编译器,给定一个IEnumerable&lt;T&gt;,它将返回List&lt;T&gt;,所以在这种情况下,它返回一个List&lt;long&gt;

【讨论】:

    【解决方案2】:

    这将帮助您更好地理解 lambda 表达式。 Anatomy of the Lambda Expression

    这是给Linq

    希望这会有所帮助。

    谢谢。

    【讨论】:

      【解决方案3】:

      Where 子句存在于 Enumerable 类中,用于在 .net 框架中进行查询。它提供布尔条件和返回源。最终会转换成各自的sql查询。

      所以你的 linq

      var salaries = customerList
                          .Where(c => c.Age > 30)
                          .Select(c => c.Salary) // salary is of type long
                          .ToList();
      

      老派 sql 命令

      SELECT [c].[Salary] FROM [CustomerList] WHERE [c].[Age] > '30'
      

      【讨论】:

        【解决方案4】:

        link from @Amit 可以给出一个好主意。

        简短的回答是 LINQ 建立在名为 Expressions 的编译器功能之上。当你编写类似Where(c =&gt; c.Age &gt; 18) 的东西时,编译器实际上并没有像常规方法那样编译c=&gt; c.Age &gt; 18

        它构建了一个语法树来描述该代码的作用。

        Where 函数使用它来构建一个 SQL 查询,该查询发送到 SQL 服务器,该服务器执行该查询以获取结果。

        建议您查看IQueryableExpression&lt;TDelegate&gt; 的工作原理以获取更多信息。

        也有助于理解difference between IEnumerable and IQueryable

        另一个在 C# 的其他部分中使用的表达式示例,例如使用 LabelFor(...) 之类的函数的 Razor 页面,它使用您表示的属性来构建 HTML 标签而不是执行代码。

        HTH

        【讨论】:

          【解决方案5】:

          “Where”如何访问 customerList 以及它如何定义 “c”的类型?

          • customerList 是 List 类型,Where() 是 List 类型的扩展方法。所以Where() 方法可以被customerList 访问。 c =&gt; c.Age &gt; 30 是在 Where() 子句中定义的谓词。这个谓词帮助列表根据条件过滤掉数据。这里c 表示List 中存在的单个元素。

          “Select”究竟是如何知道它必须只返回 “工资”?

          • Select 用于从列表中投影单个元素,在您的情况下,每个 customer 都来自 customerList。由于 Customer 类包含名为 Salary 的 long 类型的属性,因此 Select 谓词将创建新形式的对象,该对象将仅包含来自 Customer 类的 Salary 属性的值。

          如何将变量“salaries”的类型设置为 List?

          • Select() 将创建新表单,其中只有 Salary 属性,例如
          new {
                public long Salary{get; set;}
              }
          

          .ToList() 会将 Select 返回的 IEnumerable 转换为 List。最终你会得到List&lt;long&gt;

          “Where”在应用后返回一个临时的客户列表 Select 作用于哪个过滤器?

          • 是的,将在哪里返回您应用Select() 方法的过滤列表(精确的IEnumerable

          我建议你阅读Linq in C#Where clauseSelect methodList

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-02-07
            • 2018-03-11
            • 1970-01-01
            • 2020-11-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多