Почему параметр i сохраняется при вызове функции делегата в лямбда-выражении? - PullRequest
0 голосов
/ 31 августа 2018

У меня следующий код C #, и я обнаружил, что значение параметра i переносится на следующий вызов делегата лямбда-выражения.

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 будет передаваться для каждого вызова делегата. Я знаю, что локальные переменные, используемые в лямбда-выражении, сохраняются во всех вызовах из-за замыканий, но это параметр.

Вопрос:

Почему значение параметра i сохраняется во всех вызовах делегата?

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Я ожидал, что новый параметр мне будет передаваться для каждого вызова делегата. Я знаю, что локальные переменные, используемые в лямбда-выражении, сохраняются во всех вызовах из-за замыканий, но это параметр.

Параметр не сохраняется между вызовами. Второй параметр (int i), однако, является индексом , и поэтому он увеличивается с помощью логики самой функции .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;
        }
        <b>i++;</b>
    }
}

Примечание : Если мы проверяем исходный код, мы видим, что он делегирует функцию WhereIterator, которая выполняет логику. Я слышал, предоставил более «чистую» реализацию, чтобы объяснить идею.

Обратите внимание на i++: индекс увеличивается на функцию Where. Независимо от того, что делается с i в функции, мы каждый раз вызываем ее с другим значением. int не является справочным объектом, поэтому вы не можете обновить"состояние" числа.

Возьмем, к примеру, следующий вызов:

csharp> arrayOne.Where ((string n, int i)=> {i += 2; return i <= 4;} )
{ "One", "Two", "Three" }

Здесь мы увеличиваем i на 2, и мы видим, что на самом деле индексы, которые меньше 2 (или индексы, увеличенные на два, меньше 4), остаются теми же. Таким образом, индекс не делает прыжки из двух или трех.

0 голосов
/ 31 августа 2018

есть два переопределения 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 не сохраняется

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...