我正在使用101 LINQ Samples in the MSDN page学习LINQ,我遇到了这段代码:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
foreach (var n in firstSmallNumbers)
{
Console.WriteLine(n);
}
这个函数的目的是“使用TakeWhile返回从数组开头开始的元素,直到命中的数字小于它在数组中的位置。”
n
和index
究竟知道采用哪个参数? (即n
如何知道5, 4, 1, 3, 9, 8, 6, 7, 2, 0
将如何知道index
如何知道它将增加0,1,2,3 ...)?
答案 0 :(得分:9)
因为过载是这样定义的。来自MSDN
public static IEnumerable<TSource> TakeWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate
)
predicate
参数描述如下:
测试条件的每个源元素的函数;第二 函数的参数表示源元素的索引。
TSource
参数是项目,int
是索引。 bool
是返回值。
当您撰写(n, index) => ...
时,n
会获取第一个参数(TSource
)而index
将获取第二个参数(int
)。
答案 1 :(得分:4)
在lambda表达式中,=>
之前的所有内容都是方法的参数。例如,(n, index) => n >= index
lambda表达式可以重写为类似于此的方法:
public bool CheckIfValueIsGreaterOrEqualToIndex(int value, int index)
{
if(value >= index)
{
return true;
}
else
{
return false;
}
}
因此,使用该方法,您可以为参数指定任何名称(在本例中,我使用value
而不是n
)。而不是lambda,你可以在这里使用该方法:
numbers.TakeWhile(CheckIfValueIsGreaterOrEqualToIndex);
答案 2 :(得分:3)
第一个参数n
与数字上的数字相关联,第二个参数index
与序列中的数字索引相关联。实际上,如果你将它们命名为n
和index
并不重要,你可以说出任何名称。在任何情况下,第一个参数都与序列中的随机项相关联,第二个参数与该序列的索引相关联。
正如布拉德利上面所说的那样,TakeWhile
的定义如下:
public static IEnumerable<TSource> TakeWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate
)
正如我们从上面看到的,TakeWhile
是在实现IEnumerable
接口的类型上定义的扩展方法。现在注意两件事,这个方法的参数和它的返回类型。
它返回所提供序列中对象类型的一系列对象。
作为参数需要什么?
谓词。谓词是一种获取某些参数并返回true
或false
的方法。谓词的参数是什么?
谓词的参数是TSource
元素和int
。 TSource
元素将是序列的随机元素,int
将是此元素的索引。
这是(n, index) => n >= index
现在是什么?
这是一个lambda表达式,其作用类似于谓词。
Specifficaly,给定名为n
和index
的变量,如果true
则返回n>=index
,否则返回false.
将此表达式提供给TakeWhile
扩展方法就像传递Func<TSource, int, bool>
谓词一样。所以你得到你想要的东西。
答案 3 :(得分:2)
最好的方法是尝试实现自己的简化TakeWhile
方法:
public static List<int> MyTakeWhile(this List<int> input, Func<int, int, bool> predicate)
{
var result = new List<int>();
for (var i = 0; i < input.Count; i++)
{
if (predicate(input[i], i))
result.Add(input[i]);
else
break;
};
return result;
}
您将在现实生活中使用yield return
,并返回IEnumerable
,当然,使用泛型而不是int
。但这个想法是一样的。
如果你想测试它:
var numbers = new List<int> { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var result = numbers.MyTakeWhile((n, index) => n >= index);
result.ForEach(Console.WriteLine);
它应该提供{5, 4}
,它与原始TakeWhile
完全相同。