4

私はLinqの奇妙な振る舞いに出くわしました:同じように見えるかもしれない2つの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
4

1 に答える 1

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]);
}

2番目のケース(および最初のケース。実際に修正する必要があります)でクローズするラムダを作成してitemおり、foreachループが終了するまでクエリを評価していません。つまりitem、現在のアイテムではなく、常にforeachループの最後のアイテムになります。これは、新しいローカル変数を作成することで簡単に解決できます。これは、最初のケースで行うことであり、それが機能する理由です。

これは、問題をより詳細に議論する関連リンクです。(「ループ変数を閉じる」を検索すると、さらに多くの情報を見つけることができます。

これは混乱やバグの原因となることが多いため、C#5.0で変更されていることに注意してください。(これが、特定の人が問題を再現できなかった理由である可能性があります。)

これは辞書とは何の関係もないことにも注意してください。クエリでは、事実上、現在の項目ではなく、item常に最後の項目であるため、失敗します。foreachそれが現在の値であることに依存してあなたがしたことは、itemあなたが望むことをしません。

于 2012-10-31T18:33:29.177 に答える