为什么在lambda表达式中的委托函数调用之间保留参数i?

时间:2018-08-31 12:23:37

标签: c# linq lambda

我有以下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的值?

2 个答案:

答案 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)相同。因此,索引不会跳两三步。