Запрос Linq, построенный в цикле foreach, всегда принимает значение параметра из последней итерации

У меня есть список, содержащий несколько ключевых слов. Я прослежу через них, строя свой linq-запрос с ними так (свалился, чтобы удалить кодовый шум):

List keys = FillKeys() foreach (string key in keys){ q = q.Where(c => c.Company.Name.Contains(key)); } 

Когда мои ключи теперь содержат 2 ключа, которые возвращают результаты отдельно, но никогда не могут встречаться вместе (каждый элемент в q является либо «xyz», либо «123», никогда «123» и «xyz»), я все равно получаю результаты. Результат – то же самое, что и последняя строка.

Я посмотрел на запрос linq, и кажется, что он создает правильный sql, но он заменяет @ p1 AND @ p2 тем же (последним итерированным) значением.

Что я делаю не так?

Вы повторно используете одну и ту же переменную ( key ) в выражении лямбды.

Более подробную информацию см. В моей статье об анонимных методах , а также есть ряд связанных вопросов SO:

  • Ошибка LINQ to SQL (или очень странная функция) …
  • Локальные переменные с делегатами
  • C # захвачена переменная в цикле
  • Ответ на C #
  • Построение запроса LINQ программно без локальных переменных, обманывающих меня

Простое исправление – сначала скопировать переменную:

 List keys = FillKeys() foreach (string key in keys){ string copy = key; q = q.Where(c => c.Company.Name.Contains(copy)); } 

Возможно, проблема с захваченной переменной; попробуйте добавить:

 List keys = FillKeys() foreach (string key in keys){ string tmp = key; q = q.Where(c => c.Company.Name.Contains(tmp)); } 

он был исправлен в C # 5.0, а пример выше в C # 5.0 работает, но не работает в более ранних версиях C #.

Но будьте осторожны, это не касается цикла for

  static void Main() { IEnumerable query = "aaa bbb ccc"; string lettersToRemove = "ab"; Console.WriteLine("\nOK with foreach:"); foreach (var item in lettersToRemove) { query = query.Where(c => c != item); } foreach (char c in query) Console.Write(c); //OK: Console.WriteLine("\nOK with foreach and local temp variable:"); query = "aaa bbb ccc"; foreach (var item in lettersToRemove) { var tmp = item; query = query.Where(c => c != tmp); } foreach (char c in query) Console.Write(c); /* An IndexOutOfRangeException is thrown because: firstly compiler iterates the for loop treating i as an outsite declared variable when the query is finnaly invoked the same variable of i is captured (lettersToRemove[i] equals 3) which generates IndexOutOfRangeException The following program writes aaa ccc instead of writing ccc: Each iteration gets the same variable="C", i (last one frome abc). */ //Console.WriteLine("\nNOK with for loop and without temp variable:"); //query = "aaa bbb ccc"; //for (int i = 0; i < lettersToRemove.Length; i++) //{ // query = query.Where(c => c != lettersToRemove[i]); //} //foreach (char c in query) Console.Write(c); /* OK The solution is to assign the iteration variable to a local variable scoped inside the loop This causes the closure to capture a different variable on each iteration. */ Console.WriteLine("\nOK with for loop and with temp variable:"); query = "aaa bbb ccc"; for (int i = 0; i < lettersToRemove.Length; i++) { var tmp = lettersToRemove[i]; query = query.Where(c => c != tmp); } foreach (char c in query) Console.Write(c); } 
  • Выражение LINQ для возврата значения свойства?
  • ToList () - Создает ли он новый список?
  • Должен ли я использовать два предложения «где» или «&&» в моем запросе LINQ?
  • Как я могу разделить IEnumerable на группы IEnumerable
  • LINQ, чтобы найти ряд последовательных чисел
  • Запросить XDocument для элементов по имени на любой глубине
  • Невозможно неявно преобразовать тип 'System.Collections.Generic.IEnumerable ' в 'System.Collections.Generic.List
  • Создание отдельного списка настраиваемого типа в C #
  • Как реализовать левое соединение в методе расширения JOIN
  • Удалить элемент в словаре на основе значения
  • по возрастанию / убыванию в LINQ - можно изменить порядок через параметр?
  • Давайте будем гением компьютера.