3

我不确定这是不是问这个问题的正确地方,如果不是,我很抱歉。

使用与以下相同的代码:

C# LINQ 表达式问题

string[] digits = { "zero", "one", "two", "three", "four", "five", 
                    "six", "seven", "eight", "nine" };
var shortDigits = digits.Where((digit, index) => digit.Length < index);
foreach (var sD in shortDigits)
{
    Console.WriteLine(sD);
}
// Output:
// five
// six
// seven
// eight
// nine

系统是如何知道的,digit是数字中的项目,以及index数组中的位置?

4

4 回答 4

6

扩展方法的特定重载Where被定义为接受 aFunc其中第一个参数是元素,第二个参数是该元素的索引。这在文档中明确提到:

谓词

类型:System.Func<TSource, Int32, Boolean>

测试每个源元素的条件的函数;函数的第二个参数表示源元素的索引

强调我的。

于 2012-07-10T16:11:19.810 回答
2

这只是一个命名的东西,你可以命名任何东西,并索引任何东西。这只是一个匿名函数的 lambda 表达式......它可以重写:

(string digit, int index) => digit.Length < index

因此,名称与您通常在方法中设置的任何参数相同。C# 引擎识别的名称并没有什么特别之处。

(string index, int digit) => index.Length < digit

上面的方法也可以......这会令人困惑,但它会奏效。只是为了表明名称可以是您想要的任何名称

如果您指的是如何引用签名本身,那么这是由于Where 函数的重载

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

因此,本例中的 TSource 是string,使 Func 变为Func<string, int, bool>。这意味着 lambda 必须接受一个string参数后跟一个int参数,并返回一个bool

于 2012-07-10T16:11:32.767 回答
1

Where您正在使用的重载是这样实现的:

public static IEnumerable<T> Where<T>(
      this IEnumerable<T> list, Func<T,int,bool> predicate)
{
   int num = -1;
   foreach (T current in list)
   {
      num++;
      if (predicate(current, num))
      {
         yield return current;
      }
   }
   yield break;
}

如您所见,在每次迭代中,都会调用谓词(即传递的 lambda 表达式)并传递列表的当前元素和当前索引。

这样,lambda 表达式中的代码就知道元素及其索引。

于 2012-07-10T16:22:51.460 回答
0

where因为将这样的函数作为谓词存在过载:

Func<TSource, int, bool>

这个谓词的语义 ios 定义了所以第二个参数是索引。因此,如果您传递带有两个参数的 lambda,则调用 where 的版本。

于 2012-07-10T16:12:55.730 回答