【问题标题】:Where are the parameters from Enumerable.Where method defined in C#?C# 中定义的 Enumerable.Where 方法的参数在哪里?
【发布时间】:2021-07-20 09:49:08
【问题描述】:

我正在尝试更详细地了解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

感谢您的关注和支持。

【问题讨论】:

  • 2 号没有意义。您尝试将其更改为什么?
  • 将行改为“numbers.Where((myparameter, index) => myparameter
  • 那个works for me。也许您已经在代码中的其他地方声明了 myparameter 的其他内容,并且在您声明 lambda 时处于范围内?
  • 您在尝试重命名索引时收到的确切错误消息是什么?

标签: c# .net where-clause enumerable


【解决方案1】:

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

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

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

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

numbers 被传递给source(number, index) =&gt; number &lt;= index * 10 被传递给predicate。这里可以推断出类型,因为从source参数我们知道TSourceint(因为你传入了int[]),所以predicate参数的类型必须是Func&lt;int,int,bool&gt;

Func&lt;int,int,bool&gt; 表示一个接受两个int 并返回一个bool 的函数。你应该给Where这样的功能。这就是为什么您可以声明两个参数(number, index) - 这些是您传递给Where 的函数的参数。至于函数是做什么的……

左箭头有什么用?

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

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

你可以只重命名index:

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

甚至重命名它们:

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

毕竟它们只是参数名称。也许你没有正确地做到这一点。

【讨论】:

    【解决方案2】:

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

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

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

    这需要一个Func&lt;source,int,bool&gt;(一个从集合中获取源元素、一个int索引并返回一个布尔值的函数)。

    为什么我可以更改 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

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

    【讨论】:

      【解决方案3】:

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

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

      public bool IsElementValid(int number, int index)
      {
          return number <= index * 10;
      }
      
      IEnumerable<int> query = numbers.Where(IsElementValid);
      

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

      您可以在此处传递一个方法,因为Where 接受Func&lt;TElement, int, bool&gt; delegate。委托有效地允许您在变量中存储一个或多个方法。您可以阅读有关代表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,其中包含一些诊断消息以帮助您了解流程。

      为什么我可以在 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" 的数学符号。结合equals,就是“小于等于”。请参阅comparison operators 了解更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-26
        • 2018-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多