1

次のコードを検討してください(少し工夫されていますが、実際のプログラムを大幅に簡略化したものです)。

string[] strings = { "ab", "abcd", "abc", "ac", "b", "abcde", "c", "bc" };
string[] filters = { "a", "b", "c" };

// iteratively apply each filter
IEnumerable<string> filteredStrings = strings.ToArray();
foreach (string filter in filters)
{
    // in my real-world program lots of processing and stuff
    // happens here, hence why i need the enclosing foreach loop

    filteredStrings = filteredStrings.Where(s => s.Contains(filter));
}

ご覧のとおり、コードは文字列の配列をより小さな文字列のセットに繰り返しフィルタリングします。for-eachループが終了filteredStringsすると、すべてのフィルターを通過する文字列のサブセットになります。この例では、次のようになります。

{ "abcd", "abc", "abcde" }

ただし、取得する出力は次のとおりです。

{ "abcd", "abc", "ac", "abcde", "c", "bc" }

を含まない文字列を除外しているだけのよう"c"です。これは、最後のフィルタであることに関係していると思います。私IEnumerable.Where()は正しい方法で連鎖してはいけないと思います。ここで何が起こっているのでしょうか。また、正しい出力を取得するにはどうすればよいですか。

そして、はい、私のコードのコメントによると、そのforeachループはそのままにしておく必要があります。

4

2 に答える 2

9

whereデリゲートは、期待どおりにローカル変数をキャプチャしていません。filterLinq は遅延評価を行うため、変数は変化しており、すべての場所で最後の結果を使用しています。

反復変数をローカル変数にコピーすると、期待どおりにキャプチャされると思います。

foreach (string filter in filters)
{
    string localFilter = filter;
    filteredStrings = filteredStrings.Where(s => s.Contains(localFilter));
}
于 2013-02-02T17:13:47.790 に答える
3

ループで変更された変数を使用しています:filter

そのコピーを作成します。

foreach (string filter in filters)
{
    // in my real-world program lots of processing and stuff
    // happens here, hence why i need the enclosing foreach loop

    string f = filter;
    filteredStrings = filteredStrings.Where(s => s.Contains(f));
}
于 2013-02-02T17:14:59.423 に答える