Страницы

Поиск по вопросам

среда, 31 октября 2018 г.

Access to foreach variable in closure

Имею следующий код:
foreach (NetworkInterfaceInfo info in _comps) { Dispatcher.Invoke(() => SpeedLabel.Content += info.NetInterface.Description + " - " + info.IncomeSpeed + "kbps
"); }
На что получаю предупреждение:
Access to foreach variable in closure. May have different behaviour when compiled with different versions of compiler.
Какое "различное поведение" может произойти и в каких случаях?


Ответ

Смотрите.
Цикл foreach (NetworkInterfaceInfo info in _comps) может быть реализован так:
NetworkInterfaceInfo info; using (var iterator = _comps.GetEnumerator()) { while (iterator.MoveNext()) { info = iterator.Current; // тело вашего цикла } }
А может и так:
using (var iterator = _comps.GetEnumerator()) { while (iterator.MoveNext()) { NetworkInterfaceInfo info = iterator.Current; // тело вашего цикла } }
В старых версиях использовался первый вариант. При этом если вы выполняете closure по info (то есть, запоминаете текущее значение info в () => SpeedLabel.Content += info.NetInterface.Description...), к моменту фактической отработки функции переменной info может быть уже присвоено другое значение, совсем не то, которое вы ожидали, потому что цикл при этом уже пробежал до конца.
Во втором случае у вас на каждую итерацию свежая переменная, и «изменения» info в цикле нет. При этом каждое замыкание общается со своим экземпляром info
Это и есть то самое изменение поведения, о котором вас предупредил компилятор. Ваш код будет бежать по-разному с разными версиями языка.
Дополнительное чтение по теме:
Closing over the loop variable considered harmful Closing over the loop variable, part two

Комментариев нет:

Отправить комментарий