6

ですから、これはかなり簡単だと思います。

これが私のコードです:

Dictionary<int, IEnumerable<SelectListItem>> fileTypeListDict = new Dictionary<int, IEnumerable<SelectListItem>>();

foreach (PresentationFile pf in speakerAssignment.FKPresentation.PresentationFiles)
{
    IEnumerable<SelectListItem> fileTypes = Enum.GetValues(typeof(PresentationFileType))
                .Cast<PresentationFileType>().Select(x => new SelectListItem
        {
             Text = x.ToString(),
             Value = Convert.ToString((int)x),
             Selected = pf.Type == (int)x
        });

        fileTypeListDict.Add(pf.ID, fileTypes);
}

何が起こっているのかというと、最終的に辞書にはすべての正しいキーがありますが、すべての値はfileTypesループの最後の反復中に作成されたリストに設定されます。これは、参照として使用されているオブジェクトと関係があると確信していますが、C#を使用していたときは、この問題はこれまで見たことがありません。なぜこれが起こっているのか、そしてこの問題をどのように解決する必要があるのか​​を説明したい人はいますか?

ありがとう!

4

1 に答える 1

9

これは悪名高い「foreachキャプチャの問題」であり、C# 5 で「修正済み」です (「修正済み」は強い言葉です。以前は「バグ」だったことが示唆されているためです。実際には、これを混乱の一般的な原因)。どちらの場合も、ラムダは変数 をキャプチャしますpfが、 「この反復中の値」ではありませんpf。ただし、5 より前の C# では、変数pf技術的にループの外側にスコープが設定されています (そのため、ピリオドは 1 つだけです)。 C# 5 以降では、変数のスコープがループに設定されます (そのため、キャプチャの目的で、反復ごとに別の変数が存在します)。

C# 4 では、チートするだけです。

foreach (PresentationFile tmp in speakerAssignment.FKPresentation.PresentationFiles)
{
    PresentationFile pf = tmp;
    //... as before

現在pfは 内にスコープが設定されておりforeach、問題なく動作します。それがなければ、1 つしかありpfません。最後まで実行を延期したため、単一のpfが最後の反復になります。

別の修正方法は次のとおりです。実行を延期しないでください。

fileTypeListDict.Add(pf.ID, fileTypes.ToList()); // note the ToList

が "current"である間にpf評価されるようになったため、期待どおりの結果が得られます。

于 2012-10-29T13:58:42.770 に答える