V3220. The result of the LINQ method with deferred execution is never used. The method will not be executed.

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

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

public static void PrintNames(List<string> names, char startLetter)
{
  int it = 0;
  var filteredNames = names.Where(name => 
                      {
                        ++it;
                        Console.WriteLine($"{it}) {name}");
                        return name.StartsWith(startLetter); 
                      });

  Console.WriteLine($"Type: '{filteredNames.GetType()}'");
  Console.WriteLine(String.Join(',', names));
}

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

Однако ни вывода имён с позициями, ни фильтрации не произойдёт. В метод String.Join вместо filteredNamesпредаётся names. По этой причине отфильтрованная коллекция не будет выведена на консоль. Более того, фильтрация в принципе не будет выполнена. Подобное поведение обусловлено тем, что при вызове Where фильтрация выполняется не в момент вызова, а является отложенной. Следовательно, до тех пор, пока не будет произведено итерирование по коллекции, код делегата не выполнится.

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

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

Для исправления в String.Join нужно предавать не names, а filteredNames:

public static void PrintNames(List<string> names, char startLetter)
{
  int it = 0;
  var filteredNames = names.Where(name => 
                      {
                        ++it;
                        Console.WriteLine($"{it}) {name}");
                        return name.StartsWith(startLetter); 
                      });

  Console.WriteLine($"Type: '{filteredNames.GetType()}'");
  Console.WriteLine(String.Join(',', filteredNames));
}

При вызове String.Join будет выполнено итерирование по filteredNames, что запустит фильтрацию коллекции. Следовательно, код делегата выполнится, и элементы с позициями будут выведены на консоль. Также на консоль выведется отфильтрованная коллекция.

Данная диагностика классифицируется как: