8

「LINQPocketReference」という本を読んでいて、頭を動かすのが難しいという特定の例(以下で少し変更)があります...本の説明は少し短いので、疑問に思いました。誰かが私のためにそれを段階的に分解して、それが理にかなっているようにすることができます...

    IEnumerable<char> query2 = "Not what you might expect";
    foreach (char vowel in "aeiou")
    {
        var t = vowel;
        query2 = query2.Where(c => c != t);
        // iterate through query and output (snipped for brevity)
    }

これを出力します:

    あなたが期待するかもしれないwhtではない
    あなたがxpctするかもしれないwhtではない
    あなたはxpctをmghtしません
    Nt wht yu mght xpct
    Nt wht y mght xpct

これは私には完全に理にかなっています...しかし、これはそうではありません。

    IEnumerable<char> query2 = "Not what you might expect";
    foreach (char vowel in "aeiou")
    {
        query2 = query2.Where(c => c != vowel);
        // iterate through query and output (snipped for brevity)
    }
    あなたが期待するかもしれないwhtではない
    あなたがxpctするかもしれないものではありません
    あなたが期待するものではありません
    ユウが期待することはない
    期待するものではない

そうではありません...

誰かが私にここで何が起こっているのかを正確に説明してもらえますか?

4

2 に答える 2

10

最初の例で起こることは、母音の値がローカル(forループのスコープに対して)変数にキャプチャされることです。

クエリのwhere句は、キャプチャされた変数を使用します。このようなwhere句は、ローカル変数をキャプチャできる匿名メソッド/ラムダメソッドを使用します。次に起こることは、変数の現在の値をキャプチャすることです。

ただし、2番目のクラスでは、現在の値をキャプチャせず、使用する変数のみをキャプチャします。したがって、この変数は変更されるため、ループを実行するたびに、最後のクラスの上に新しいWhere句を作成します。ただし、変数を変更するので、前述のすべても変更します。

したがって、最初の例では、次のタイプのクエリを取得します。

IEnumerable<char> query2 = "Not what you might expect";
Char t1 = 'a'; query2 = query2.Where(c => c != t1);
Char t2 = 'e'; query2 = query2.Where(c => c != t2);
Char t3 = 'i'; query2 = query2.Where(c => c != t3);
Char t4 = 'o'; query2 = query2.Where(c => c != t4);
Char t5 = 'u'; query2 = query2.Where(c => c != t5);

2番目の例では、次のようになります。

IEnumerable<char> query2 = "Not what you might expect";
Char vowel = 'a'; query2 = query2.Where(c => c != vowel);
vowel = 'e'; query2 = query2.Where(c => c != vowel);
vowel = 'i'; query2 = query2.Where(c => c != vowel);
vowel = 'o'; query2 = query2.Where(c => c != vowel);
vowel = 'u'; query2 = query2.Where(c => c != vowel);

この2番目の例を実行するときまでに、の値はvowel'u'になるため、uのみが削除されます。ただし、「u」を削除するために同じ文字列上に5つのループがありますが、もちろん最初のループだけがそれを実行します。

この変数のキャプチャは、匿名メソッド/ラムダを使用するときに私たち全員がつまずくものの1つであり、詳細については、C#の詳細:クロージャの美しさを参照してください。

そのページを下に移動して、キャプチャ戦略の比較:複雑さとパワーの比較の下にあるテキストを参照すると、この動作の例がいくつか見つかります。

于 2008-12-23T19:08:38.910 に答える
1

実際、それを読み直すと、それは理にかなっています。一時変数を使用するということは、一時変数自体がクエリ内にキャプチャされることを意味します...ループを5回評価しているため、クエリのバージョンごとに5つのインスタンス化された一時変数参照があります。

一時変数がない場合は、ループ変数への参照のみがあります。

したがって、5つの参照と1つの参照。そのため、次のような結果が得られます。

最初のケースでは、ループが完全に評価されると、クエリは一時変数への5つの参照を使用するため、それぞれa、e、i、o、およびuが削除されます。

2番目のケースでは、同じことを行っています... 5つの参照すべてが同じ変数を参照しており、明らかに1つの値しか含まれていません。

話の教訓:「価値」ではなく「参照」を考えてください。

それで、これは今他の誰にとっても意味がありますか?

于 2008-12-23T19:09:04.307 に答える