C# 中定义的 Enumerable.Where 方法的参数在哪里?

问题描述

我试图更详细地了解 Enumerable.Where 方法的使用。尽管我已经了解了许多细节,包括 lambda 表达式的使用、委托、谓词等,但有些事情对我来说毫无意义,我将不胜感激。

首先我指的是下面链接中的解释:

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where?view=net-5.0

在上面的网页中,他们有以下代码示例:

int[] numbers = { 0,30,20,15,90,85,40,75 };

IEnumerable<int> query =
    numbers.Where((number,index) => number <= index * 10);

foreach (int number in query)
{
    Console.WriteLine(number);
}
/*
 This code produces the following output:

 0
 20
 15
 40
*/

我的问题是:

  1. 参数“number”和“index”在哪里定义的?我知道 Where 中的“数字”与 foreach 语句中的“数字”不同。

  2. 为什么我可以改变Where里面的参数“number”的名字,却不能改变“index”的名字?

  3. 为什么这段代码会产生输出 0、20、15、40?我知道索引是从 0 到 7。

  4. “number

感谢您的关注和支持

解决方法

参数“number”和“index”在哪里定义的?

它们在您编写 (number,index) => ... 时声明。 (number,index) =>(int number,int index) => 的缩写。可以省略类型,因为它们可以从 Where 的签名中推断出来。

您正在调用的 Where 的重载是:

public static IEnumerable<TSource> Where<TSource> (
    this IEnumerable<TSource> source,Func<TSource,int,bool> predicate
);

numbers 传递给 source,而 (number,index) => number <= index * 10 传递给 predicate。在这里可以推断类型,因为根据 source 参数,我们知道 TSourceint(因为您传入了 int[]),所以 predicate 的类型}} 参数必须是 Func<int,bool>

Func<int,bool> 表示一个函数,它接受两个 int 并返回一个 bool。你应该给 Where 这样的函数。这就是为什么允许您声明两个参数 (number,index) - 这些是您传递给 Where 的函数的参数。至于功能是做什么的...

左箭头有什么用?

它是“小于或等于”运算符。如果 Where 小于或等于数字索引的 10 倍,则您传递给 number 的函数返回 true。您应该明白为什么在过滤后的序列中只剩下 0(在索引 0)、20(在索引 2)、15(在索引 3)和 40(在索引 6)。这也应该回答你的第三个问题。

为什么我可以改变Where里面的参数“number”的名字,却不能改变“index”的名字?

您可以只重命名index

(number,b) => number <= b * 10

甚至重命名它们:

(a,b) => a <= b * 10

它们毕竟只是参数名称。也许你没有做对。

,

参数“number”和“index”在哪里定义的?我知道 Where 中的“数字”与 foreach 语句中的“数字”不同。

想象一下代码看起来更像这样:

public bool IsElementValid(int number,int index)
{
    return number <= index * 10;
}

IEnumerable<int> query = numbers.Where(IsElementValid);

您的代码 (number,index) => number <= index * 10; 有效地​​声明了一个匿名方法,该方法接受两个参数:numberindex,并返回一个 bool。这些称为“lambda 表达式”,您可以在 documentation 中阅读有关它们的更多信息。

您可以在此处传递方法,因为 Where 接受 Func<TElement,bool> delegate。委托有效地允许您在变量中存储一个或多个方法。您可以阅读有关代表 here 的信息。

所以现在我们知道 Func 可以有效地保存一个方法,我们可以通过编写我们自己的方法来消化 Where 是如何工作的:

public List<int> MyOwnWhere(int[] source,Func<int,bool> filter)
{
    var result = new List<int>();
    for (int i = 0; i < source.Length; ++i)
    {
        if (filter(source[i],i) == true)
        {
            result.Add(source[i]);
        }
    }
    return result;
}

当然,这并不是 Where 的工作原理,但您可以了解 Func 背后发生的事情。

我创建了一个示例 here,其中包含一些诊断消息以帮助您了解流程。

为什么我可以改变Where里面的参数“number”的名字,却不能改变“index”的名字?

你可以在不破坏东西的情况下改变它。 Here 我已将它们更改为“bob”和“simon”,但仍然有效。

为什么这段代码会产生输出 0、20、15、40?我知道索引是从 0 到 7。

您的检查是这样执行的:

Index | Check
0     | 0 <= 0   (because 0 * 10 == 0)  result = true
1     | 30 <= 10 (because 1 * 10 == 10) result = false
2     | 20 <= 20 (because 2 * 10 == 20) result = true
3     | 15 <= 30 (because 3 * 10 == 30) result = true
4     | 90 <= 40 (because 4 * 10 == 40) result = false
5     | 85 <= 50 (because 5 * 10 == 50) result = false
6     | 40 <= 60 (because 6 * 10 == 60) result = true
7     | 75 <= 70 (because 7 * 10 == 70) result = false

“number

左箭头是 "less than" 的数学符号。与等号结合起来就是“小于或等于”。请参阅 comparison operators 了解更多信息。

,

参数“number”和“index”在哪里定义的?我知道 Where 中的“数字”与 foreach 语句中的“数字”不同。

即来自可枚举的扩展方法 where:

public static System.Collections.Generic.IEnumerable<TSource> Where<TSource> (this System.Collections.Generic.IEnumerable<TSource> source,bool> predicate);

这需要一个 Func<source,bool>(一个函数,它从集合中获取一个源元素、一个 int 索引并返回一个 bool)。

为什么我可以更改Where里面的参数“number”的名称,但不能更改“index”的名称?

表示可枚举中的索引。

为什么这段代码会产生输出 0、20、15、40?我知道索引是从 0 到 7。

{ 0,30,20,15,90,85,40,75 }

当谓词 (number

index 0 number  0:  0 <= 0 * 10 : true
index 1 number 30: 30 <= 1 * 10 : false
index 2 number 20: 20 <= 2 * 10 : true
index 3 number 15: 15 <= 3 * 10 : true
index 4 number 90: 90 <= 4 * 10 : false
index 5 number 85: 85 <= 5 * 10 : false
index 6 number 40: 40 <= 6 * 10 : true
index 7 number 75: 75 <= 7 * 10 : false

“number

数字小于或等于索引乘以十——它小于或等于比较返回一个布尔值。