“哪里”和“选择”在 LINQ 中是如何工作的?

Sha*_*ath 2 c# linq

我有以下代码片段。我对后面提到的代码片段几乎没有疑问。

var salaries = customerList
                    .Where(c => c.Age > 30)
                    .Select(c => c.Salary) // salary is of type long
                    .ToList();
Run Code Online (Sandbox Code Playgroud)
  • 在上面的代码片段中,“Where”如何访问 customerList 以及它如何定义“c”的类型?
  • 在应用 Select 所作用的过滤器后,“Where”是否会返回一个临时的客户列表?
  • “Select”究竟是如何知道它只需要返回“Salary”的?
  • 变量“salaries”的类型如何设置为 List<long>?

Swe*_*per 6

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这Where是一个扩展方法。您基本上是在调用Where(customerList, c => c.Age > 30). 现在您应该看到它在哪里可以访问customerList. 它还T通过查看“是什么”来推断应该是什么IEnumerable customerList。因为它是 a IEnumerable<Customer>Tis Customer,所以它期望 aFunc<Customer, bool>作为第二个参数。这就是它知道的c方式Customer

Where不返回临时列表。许多 LINQ 方法使用延迟评估。Where返回一个IEnumerable<Customer>被过滤的。请记住,这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);
    }
}
Run Code Online (Sandbox Code Playgroud)

变量的类型salaries是通过查看您调用的每个方法的方法签名来确定的。您的Select调用返回 a IEnumerable<long>,并且其ToList签名告诉编译器,给定 aIEnumerable<T>它将返回List<T>,因此在这种情况下,它返回 a List<long>