Linq与词典的奇怪行为

时间:2012-10-31 18:22:59

标签: c# linq dictionary

我遇到过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

1 个答案:

答案 0 :(得分: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做的任何依赖它的东西都不是你想要的。