【问题标题】:Linq strange behviour with dictionariesLinq 字典的奇怪行为
【发布时间】:2012-10-31 18:22:59
【问题描述】:

我遇到了 Linq 的一个奇怪行为:两个可能看起来相同的 linq 表达式我有不同的结果!如果我循环一次得到相同的结果,但在上面什么都找不到。

代码如下:

        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

【问题讨论】:

  • 只需复制/粘贴您的代码,它就会输出 true,true......
  • 我在三台电脑上试了试:True, False (DOT.NET 4.0) 并在您发表评论后再次尝试。
  • L.B.可能正在使用 c# 5。他们改变了处理闭包的方式:blogs.msdn.com/b/ericlippert/archive/2009/11/12/…

标签: c# linq dictionary


【解决方案1】:

问题是您正在关闭循环变量。

有问题的代码部分就在这里:

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 所做的任何依赖于它作为当前值的操作都不会达到您想要的效果。

【讨论】:

  • 感谢您及时简洁的回复!
猜你喜欢
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多