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 中已“修复”(“修复”是一个强词,因为它暗示它以前是一个“错误”:实际上 - 规范现在已更改为承认这是一个混淆的常见原因)。在这两种情况下,lambda 都会捕获变量 pf而不是pf在此迭代期间的值”-但在 C# before-5 中,变量pf技术上被限定在循环之外(因此只有其中一个,句点),其中C# 5 及更高版本的变量在循环内的范围(因此有一个不同的变量,用于捕获目的,每次迭代)。

在 C# 4 中,作弊:

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

nowpf范围在 内foreach,它可以正常工作。没有它,只有一个pf- 由于您已将执行推迟到最后,所以 single的pf将是最后一次迭代。

另一种解决方法是:不要推迟执行:

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

现在它pf"current"时被评估,所以会有你期望的结果。

于 2012-10-29T13:58:42.770 回答