2012-10-31 61 views
4

我遇到了一个奇怪的行为Linq:与两个linq表达式可能看起来相同我有不同的结果!如果我循环一次,我得到相同的结果,但在它上面没有发现。Linq奇怪behviour与字典

下面是代码:

 Dictionary<String, String> mainDico = new Dictionary<String, String>(); 
     mainDico.Add("key1", "value1"); 
     mainDico.Add("key2", "value2"); 

     List<Dictionary<String, String>> ls = new List<Dictionary<String, String>>(); 

     Dictionary<String, String> fistDico = new Dictionary<String, String>(); 
     fistDico.Add("key1", "value1"); 
     fistDico.Add("key2", "value2"); 

     Dictionary<String, String> secondDico = new Dictionary<String, String>(); 
     secondDico.Add("key1", "other"); 
     secondDico.Add("key2", "other"); 

     ls.Add(fistDico); 
     ls.Add(secondDico); 


     IEnumerable<Dictionary<String, String>> failQuery = from p in ls 
                  select p; 

     IEnumerable<Dictionary<String, String>> successfulQuery = from p in ls 
                  select p; 

     String[] items = new String[] { "key1","key2" }; // with one element it works 

     foreach (var item in items) 
     { 
      String temp = mainDico[item]; 
      failQuery = failQuery.Where(p => p[item] == temp); 
      successfulQuery = successfulQuery.Where(p => p[item] == mainDico[item]); 
     } 

     Console.WriteLine(successfulQuery.SingleOrDefault() != null);//True 
     Console.WriteLine(failQuery.SingleOrDefault() != null);//False 
+0

只需复制/粘贴你的代码,它输出true,true。 ..... –

+1

我试了三台电脑:真,假(DOT.NET 4.0)并在您的评论后再次尝试。 – Akli

+4

L.B.可能使用c#5.他们改变了他们处理闭包的方式:http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx –

回答

5

的问题是,您要关闭了循环变量。

有问题的代码段就在这里:

foreach (var item in items) 
{ 
    String temp = mainDico[item]; 
    failQuery = failQuery.Where(p => p[item] == temp); 
    successfulQuery = successfulQuery.Where(p => p[item] == mainDico[item]); 
} 

你创建在第二种情况下关闭了item一个lambda(也是第一种情况下,你真的应该解决这个问题),你在foreach循环结束之前,不会评估查询;这意味着item将始终是foreach循环中的最后一项,而不是当前项目。通过创建一个新的局部变量可以很容易地解决这个问题,这就是你在第一种情况下所做的,这就是为什么这是可行的。

这是一个related link,更详细地讨论此事。 (您可以通过搜索过“关过循环变量”中找到其它更多地方。

注意this was changed in C# 5.0,因为它是混乱和错误的一个常见原因。(这可能是为什么有些人不能重现该问题。)

另外值得一提的是,这有什么好做的字典。在您的查询item实际上总是在foreach的最后一个项目,而不是现在的,这就是为什么它会失败。您使用item做了什么是依赖它是当前值不会做你想要的。

+0

感谢您的快速和简洁的回应! – Akli