所以,我觉得这个很直接。
这是我的代码:
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#之前没有看到过这个问题。任何人都在意解释为什么会这样,以及我应该如何解决这个问题?
谢谢!
答案 0 :(得分:9)
这是臭名昭着的“foreach
捕获问题”,并在C#5中“修复”(“修复”是一个强有力的词,因为它表明它之前是一个“错误”:实际上 - 规范现在改为承认这是混乱的常见原因)。在这两种情况下,lambda都会捕获变量 pf
,而不是“此迭代期间pf
的值” - 但在C#之前 - 5变量pf
技术范围在循环外(因此只有其中一个,句点),其中 - 如在C#5及以上变量是在循环中设置(因此,为了捕获目的,每次迭代都有一个不同的变量)。
在C#4中,只是作弊:
foreach (PresentationFile tmp in speakerAssignment.FKPresentation.PresentationFiles)
{
PresentationFile pf = tmp;
//... as before
现在pf
的范围是foreach
,它可以正常工作。没有它,只有一个pf
- 并且因为你将执行推迟到结束,单个pf
的值将是最后一次迭代。
另一种解决方法是:不要推迟执行:
fileTypeListDict.Add(pf.ID, fileTypes.ToList()); // note the ToList
现在评估而pf
是“当前”,因此会得到您期望的结果。