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

Where are the parameters from Enumerable.Where method defined in C#?

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

首先我指的是下面link的解释:

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 <= index * 10”中左箭头的用法是什么,这个左箭头的官方名称是什么? (我知道右箭头是在lambda表达式中分隔输入和输出)

感谢您的关注与支持

Where are the parameters "number" and "index" defined? I understand that the "number" inside the Where is different from the "number" inside the foreach statement.

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

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

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

您的代码 (number, index) => number <= index * 10; 有效地声明了一个接受两个参数的匿名方法:numberindex 以及 returns 和 bool。这些称为“lambda 表达式”,您可以在 documentation.

中阅读更多关于它们的信息

你可以在这里传递一个方法因为Where accepts a Func<TElement, int, bool> delegate. A delegate effectively allows you to store one or more methods in a variable. You can read about delegates here.

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

public List<int> MyOwnWhere(int[] source, Func<int, 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,其中包含一些诊断消息以帮助您了解流程。

Why I can change the name of the parameter "number" inside the Where but can't change the name of "index"?

您可以在不破坏任何东西的情况下对其进行更改。 Here 我已将它们更改为“bob”和“simon”,它仍然有效。

Why does this code produces the output 0, 20, 15, 40? I know the indexes are from 0 to 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

What is the usage of the left arrow in "number <= index * 10" and what is the official name of this left arrow? (I know the right arrow is to separe input and output in a lambda expression)

左边的箭头是"less than". Combined with the equals, it is "less than or equal to". See comparison operators的数学符号。

Where are the parameters "number" and "index" defined?

它们在您编写 (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[]),所以 [=21] 的类型=]参数必须是Func<int,int,bool>.

Func<int,int,bool>表示一个函数,取两个int和returns一个bool。你应该给 Where 这样的功能。这就是为什么您可以声明两个参数 (number, index) - 这些是您传递给 Where 的函数的参数。至于功能是做什么的...

What is the usage of the left arrow?

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

Why I can change the name of the parameter "number" inside the Where but can't change the name of "index"?

您可以重命名 index:

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

甚至重命名它们:

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

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

Where are the parameters "number" and "index" defined? I understand that the "number" inside the Where is different from the "number" inside the foreach statement. <

即来自可枚举扩展方法 Where:

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

这需要一个 Func<source,int,bool>(一个从集合中获取源元素的函数,一个 int 索引和 returns 一个 bool)。

Why I can change the name of the parameter "number" inside the Where but can't change the name of "index"? <

表示枚举中的索引。

Why does this code produces the output 0, 20, 15, 40? I know the indexes are from 0 to 7.

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

where 仅在谓词 (number <= index * 10) 为真时产生结果(列表中的数字)

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

What is the usage of the left arrow in "number <= index * 10" and what is the official name of this left arrow? (I know the right arrow is to separate input and output in a lambda expression) <

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