2008-11-17 78 views
15

我有一个List,其中包含几个关键字。 我通过他们的foreach建立我的LINQ查询与他们像这样(归结为删除代码噪声):在foreach循环中构建的Linq查询始终从上次迭代中获取参数值

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

当我现在做我的钥匙包含2个键即seperatly返回结果,但永远不能occure在一起( q中的每一项都是“xyz”或“123”,从不“123”和“xyz”),我仍然得到结果。结果集与最后一个字符串相同。

我看了一下linq查询,看起来它创建了正确的sql,但它用相同的(最后一次被读取的)值替换@ p1和@ p2。

我在做什么错?

+0

可能重复http://stackoverflow.com/questions/271440/c-sharp-captured-可变回路) – nawfal 2013-11-02 06:07:17

回答

31

您正在重新使用lambda表达式中的相同变量(key)。

查看我在anonymous methods文章了解更多详细信息,并有一些相关的SO问题太多:

的简单的解决方法是复制的第一变量:

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

嘿嘿,同时发现这一个:http://stackoverflow.com/questions/190227/building-a-linq-query-programatically-without-local-variables-tricking-me 简单(但赚取)贷款给你;) – 2008-11-17 13:54:45

+0

再次让我感到... – 2008-11-17 13:55:27

12

可能捕获的可变问题;尝试添加:

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

它已在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); 
     } 
[C#捕获变量循环](的