Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top

Вебинар: Интеграция статического анализа и DevSecOps: PVS-Studio и AppSec.Hub в действии - 16.04

>
>
>
V3219. The variable was changed after i…
menu mobile close menu
Проверка проектов
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Микрооптимизации (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Реализовано по запросам пользователей (C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C++)
Стандарт OWASP (C#)
Стандарт OWASP (Java)
Проблемы при работе анализатора кода
Дополнительная информация
toggle menu Оглавление

V3219. The variable was changed after it was captured in a LINQ method with deferred execution. The original value will not be used when the method is executed.

02 Апр 2025

Анализатор обнаружил изменение захваченной переменной, которая использовалась в LINQ методе с отложенным выполнением. При таком сценарии изначальное значение переменной не будет учитываться.

Рассмотрим пример:

private static List<string> _names = new() { "Tucker", "Bob", "David" };

public static void ProcessNames()
{
  string startLetter = "T";
  var names = _names.Where(c => !c.StartsWith(startLetter));

  startLetter = "B";
  names = names.Where(c => !c.StartsWith(startLetter))
               .ToList();
}

В методе ProcessNames производится фильтрация имён по первой букве. Ожидается, что в результате переменная names будет содержать имена, не начинающиеся на T и B. Однако поведение программы будет иным. При выполнении этого метода в names будет коллекция, состоящая из Tucker и David.

Подобное поведение обусловлено тем, что при вызове Where фильтрация выполняется не в момент вызова, а является отложенной. Так как между двумя вызовами Where переменной startLetter присваивается B, значение T не учитывается при итоговом вычислении.

Это происходит из-за того, что startLetter захвачена при первом вызове Where, и её значение изменилось перед вторым вызовом Where. Как следствие, будет получена коллекция, которая фильтруется только по B.

Подробнее об отложенном выполнении можно узнать здесь.

Чтобы метод работал корректно, нужно либо немедленно выполнить запрос (первый Where) и работать с результатом выполнения, либо использовать другую переменную в лямбда-выражении второго Where.

Рассмотрим первый сценарий:

private static List<string> _names = new() { "Tucker", "Bob", "David" };

public static void ProcessNames()
{
  string startLetter = "T";
  var names = _names.Where(c => !c.StartsWith(startLetter))
                    .ToList();

  startLetter = "B";
  names = names.Where(c => !c.StartsWith(startLetter))
               .ToList();
}

После первого метода Where вызывается ToList, при выполнении которого создаётся коллекция, отфильтрованная с помощью первого Where. На момент изменения захваченной переменной коллекция уже сформирована, следовательно, фильтрация будет выполняться корректно.

Рассмотрим второй вариант исправления:

private static List<string> _names = new() { "Tucker", "Bob", "David" };

public static void ProcessNames()
{
  string startLetter1 = "T";
  var names = _names.Where(c => !c.StartsWith(startLetter1));

  string startLetter2 = "B";
  names = names.Where(c => !c.StartsWith(startLetter2))
               .ToList();
}

В данном случае захваченной переменной не присваивается новое значение между вызовами Where, вместо этого используется переменная startLetter2. В результате фильтрация отработает корректно.

close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Я хочу принять участие в тестировании
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам