Здравствуйте, Аноним, Вы писали:
А>Но почему такой код работает, как нужно:
Всё зависит от области действия (scope) переменной.
В первом случае лямбда захватывает переменную, общую для всего цикла. Во втором — параметр, его область действия ограничена самим методом.
P.S. Начиная с 5го шарпа лямбда внутри тела foreach будет использовать локальную копию переменной цикла.
Здравствуйте, GGoga, Вы писали:
GG>Кратко: при передаче в метод SaveAction переменная типа int копируется, при захвате лямбдой — нет.
Неверно. В примере выше лямбда не захватывает index.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, GGoga, Вы писали:
GG>>Кратко: при передаче в метод SaveAction переменная типа int копируется, при захвате лямбдой — нет. S>Неверно. В примере выше лямбда не захватывает index.
Что неверно то? При чем здесь index? Я имел в виду переменную item.
GG>Здравствуйте, Sinix, Вы писали:
GG>>>Кратко: при передаче в метод SaveAction переменная типа int копируется, при захвате лямбдой — нет. S>>Неверно. В примере выше лямбда не захватывает index.
GG>Что неверно то? При чем здесь index? Я имел в виду переменную item.
PS.: index вообще нигде не выступает частью лямбды. К чему коммент то был?
Здравствуйте, GGoga, Вы писали:
GG>>Здравствуйте, Sinix, Вы писали:
GG>>>>Кратко: при передаче в метод SaveAction переменная типа int копируется, при захвате лямбдой — нет. S>>>Неверно. В примере выше лямбда не захватывает index.
GG>>Что неверно то? При чем здесь index? Я имел в виду переменную item.
GG>PS.: index вообще нигде не выступает частью лямбды. К чему коммент то был?
А вы увидели переменную типа int (см. выделенное)?
Re[6]: foreach и лямбды
От:
Аноним
Дата:
28.09.12 09:16
Оценка:
А>А где вы увидели переменную типа int (см. выделенное)?
Здравствуйте, Аноним, Вы писали:
А>>А вы увидели переменную типа int (см. выделенное)?
GG>Ок, немного "промахнулся". Но суть от этого не изменилась. GG>Перефразирую. GG>здесь:
GG>
Здравствуйте, xvost, Вы писали:
X>Привет GC
То же поведение можно получить и сейчас, достаточно использовать в лямбде локальную переменную, а не переменную цикла. Пока что никто не умер
Кроме того, GC не интересует количество дохлых объектов, в особенности — в GC0. На практике стоимость сборки 12 байт замыкания + (16 байт делегатов * (количество итераций)) или (12 + 16 байт) * (количество итераций) будет примерно одинакова (цифры для x86).
Здравствуйте, Sinix, Вы писали:
S>То же поведение можно получить и сейчас, достаточно использовать в лямбде локальную переменную, а не переменную цикла. Пока что никто не умер
До тех пока лямбда гарантированно выполнится при неизмененном состоянии переменной цикла, старое поведение вполне годилось. И при этом было эффективнее.
S>Кроме того, GC не интересует количество дохлых объектов, в особенности — в GC0.
Это заблуждение.
Гугли по словам mid-life crisis и memory pressure
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, xvost, Вы писали:
X>Здравствуйте, Sinix, Вы писали:
S>>То же поведение можно получить и сейчас, достаточно использовать в лямбде локальную переменную, а не переменную цикла. Пока что никто не умер
X>До тех пока лямбда гарантированно выполнится при неизмененном состоянии переменной цикла, старое поведение вполне годилось. И при этом было эффективнее.
Если нужно старое поведение, то всегда можно вынести переменные для замыкания за тело цикла.
Тут два варианта:
— старый, "вводим локальную переменную для предупреждения глобальных замыканий".
— новый, "вводим глобальную переменную для глобальных замыканий".
Новый мне нравится больше
X>Это заблуждение. X>Гугли по словам mid-life crisis и memory pressure
Кроме того, GC не интересует количество дохлых объектов, в особенности — в GC0.
Насколько вероятно, что замыкания, которые живут только в теле цикла, переедут в следующие поколения?
Здравствуйте, Sinix, Вы писали:
GG>>Лямбда будет ссылаться на Enumerator.Current, т.е. всегда на 1 и тот же элемент. S>Уже ближе, но не совсем
S>Для массивов компилятор заменяет foreach на for, enumerator-а здесь в принципе не будет. S>... S>Проблема — в областях видимости переменных, не в их копировании.
1) На сколько я помню, компилятор ничего не заменяет, все это делает JIT.
2) Правильно ли понимаю, что Вы хотите сказать, что следующий код (при условии, что items — массив):
tmp1 != tmp2 ->> два разных объекта-ссылки, но ссылающихся на один и тот же объект-строку в памяти. Именно это я и хотел сказать, а Вы это пытаетесь "опротестовать".
Здравствуйте, Sinix, Вы писали:
X>>До тех пока лямбда гарантированно выполнится при неизмененном состоянии переменной цикла, старое поведение вполне годилось. И при этом было эффективнее. S>Если нужно старое поведение, то всегда можно вынести переменные для замыкания за тело цикла.
Ага, особенно в foreach'е
X>>Это заблуждение. S>Насколько вероятно, что замыкания, которые живут только в теле цикла, переедут в следующие поколения?
Я говорил не о том. Я говорил что большое кол-во объектов замыкания может вытеснить в GC1 другие объекты, которые без этого траффика сдохли бы в GC0
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, GGoga, Вы писали:
GG>1) На сколько я помню, компилятор ничего не заменяет, все это делает JIT.
Заменяет, там самый настоящий ldelem.i4
// IN:static void Main(string[] args)
{
var items =new[] { 1, 2, 3, 4, 5 };
var sum = 0;
foreach (var item in items)
{
sum += item;
}
Console.WriteLine(sum);
}
// OUT:
// capttest1.Programprivate static void Main(string[] args)
{
int[] items = new int[]
{
1,
2,
3,
4,
5
};
int sum = 0;
int[] array = items;
for (int i = 0; i < array.Length; i++)
{
int item = array[i];
sum += item;
}
Console.WriteLine(sum);
}
GG>2) Правильно ли понимаю, что Вы хотите сказать, что следующий код (при условии, что items — массив): GG>Будет преобразован в такой:
Почти в такой. Будет
for (int i = 0; i < items.Length; i++)
{
string item = items[i];
_actions[index] = () => Console.WriteLine(item);
index++;
}
GG>это все равно, что: GG>tmp1 != tmp2 ->> два разных объекта-ссылки, но ссылающихся на один и тот же объект-строку в памяти. Именно это я и хотел сказать, а Вы это пытаетесь "опротестовать".
Так я не опротестовываю, я уточняю
Здравствуйте, xvost, Вы писали:
S>>Если нужно старое поведение, то всегда можно вынести переменные для замыкания за тело цикла. X>Ага, особенно в foreach'е
X>Я говорил не о том. Я говорил что большое кол-во объектов замыкания может вытеснить в GC1 другие объекты, которые без этого траффика сдохли бы в GC0
Так с этого надо было начинать(с) Я вообще не понимаю о чём мы тут спорим, "старое" поведение тоже вытеснит, только чуть помедленней