我有以下C#代码,并且发现参数i
的值被传递到lambda表达式委托的下一个调用。
string[] arrayOne = {"One", "Two", "Three", "Three", "Three"};
string[] newArray = arrayOne.Where ((string n, int i)=> {return i++ <=2;} ).ToArray();
// newArray is {"One","Two", "Three"}
我的期望是,每次调用该委托都会传递一个新参数i
。我知道在lambda表达式中使用的局部变量会由于闭包而在所有调用中保留,但这是一个参数。
问题:
为什么在所有对委托的调用中都保留参数i
的值?
答案 0 :(得分:3)
有两个优先LINQ where
。
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
您调用使用第二个参数int
,类型值表示您的数组索引。
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
这将返回集合中索引值小于或等于2的值。
Where ((string n, int i)=> {return i++ <=2;})
但是i++
没有意义,因为您离开了委托函数作用域,自动增量i的值不会保留
答案 1 :(得分:2)
我的期望是,每次调用代理时都会传递一个新参数。我知道在lambda表达式中使用的局部变量会由于闭包而在所有调用中保留,但这是一个参数。
在两次调用之间不保留该参数。但是,第二个参数(int i
是一个 index ,因此,.Where(..)
函数本身的逻辑对其进行了递增。>
在Where
中,它看起来或多或少像:
public static IEnumerable<T> Where(this IEnumerable<T> data, Funct<T, int, bool> p) {
int i = 0;
foreach(T t in data) {
if(p(t, i)) {
yield return t;
}
i++;
}
}
注意:如果我们检查源代码,就会发现它委托给
WhereIterator
函数,该函数执行逻辑。我听说提供了一个更“干净”的实现方式来解释这个想法。
注意i++
:通过Where
函数将 递增索引。不管函数中的i
做什么,我们每次都用另一个值来调用它。 int
不是引用对象,因此不能更新数字的“状态”。
例如以以下呼叫为例:
csharp> arrayOne.Where ((string n, int i)=> {i += 2; return i <= 4;} )
{ "One", "Two", "Three" }
在这里,我们将i
增加2
,我们发现确实小于2
的索引(或者增加了2的索引小于4
)相同。因此,索引不会不跳两三步。