在foreach循环中构build的Linq查询总是从上次迭代中获取参数值

我有一个列表包含几个关键字。 我通过他们foreach构build我的linq查询与他们一样(煮沸下来删除代码噪音):

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

当我现在让我的键包含2键,返回结果seperatly,但永远不会一起发生(q中的每个项目是“xyz”或“123”,从来没有“123”和“xyz”),我仍然得到的结果。 结果集与最后一个string相同。

我看了一下linq查询,看起来它创build了正确的sql,但是它用相同的(最后一个被访问的)值replace@ p1和@ p2。

我究竟做错了什么?

你在lambdaexpression式中重用了相同的variables( key )。

有关更多详细信息,请参阅我的匿名方法文章,还有一些相关的SO问题:

  • LINQ to SQL的错误(或非常奇怪的function)…
  • 带有委托的局部variables
  • C#在一个循环中捕获variables
  • C#gotcha答案
  • 以编程方式构buildLINQ查询,而不用局部variables欺骗我

简单的解决办法是先复制variables:

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

可能是一个被捕获的variables问题; 尝试添加:

 List<string> 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<char> 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); }