为什么IEnumerable会丢失更新的数据?

时间:2015-04-16 12:14:17

标签: c# linq

您能否解释一下为什么执行以下代码后Selected属性未更新为true

使用的ListItem类型来自System.Web.UI.WebControls命名空间,是一个类(不是结构体)。我相信FirstOrDefault函数返回对我可以更新和传递的实例的引用在items枚举中。

// produce list items out of the communities
IEnumerable<ListItem> items = communities.Select(community => new ListItem(community.Name, community.Id.ToString()));

// mark the right list item as selected, if needed
if (platform.CommunityId > 0)
{
    string strCommunityId = platform.CommunityId.ToString();
    ListItem selectedItem = items.FirstOrDefault(item => item.Value == strCommunityId);
    if (selectedItem != null) selectedItem.Selected = true;
}

// now items do not store any updated item!

这是因为每次调用foreach时都会执行枚举器,从而创建新项而不是返回包含我更新的项的集合吗?

4 个答案:

答案 0 :(得分:17)

问题是IEnumerable 不可重复。您每次枚举时都会执行投影(community => new ListItem - 因此每次都是新的ListItemSelect是一个非缓冲的延迟投影。

您可以通过简单添加.ToList()来修复所有内容,以强制将数据放入单个列表中;

var items = communities.Select(
    community => new ListItem(community.Name, community.Id.ToString())
).ToList();

既然数据在列表中,您可以循环遍历列表 - 它始终是相同的项目,并且将保留更改。

答案 1 :(得分:5)

会发生这种情况,因为您使用的是Select

IEnumerable<ListItem> items = communities
   .Select(community => new ListItem(community.Name, community.Id.ToString()));

每次遍历项目时都会创建新对象。

答案 2 :(得分:5)

你的问题是那个

IEnumerable<ListItem> items = communities
    .Select(community => new ListItem(community.Name, community.Id.ToString()));

创建一个IEnumerable 懒惰评估 - 也就是说,每次枚举时,重新枚举原始communities序列,并Select按顺序重新执行每个项目的投影。

如果您在最后粘贴.ToList(),请将该行更改为:

IEnumerable<ListItem> items = communities
    .Select(community => new ListItem(community.Name, community.Id.ToString()))
    .ToList();

您将观察到不同的结果。虽然它仍然是IEnumerable,但它将不再是一个懒惰的评估版本,并且您在其中所做的更改将在以后的迭代中通过相同的IEnumerable进行观察。

答案 3 :(得分:3)

我认为Marc Gravell的答案是正确的,但你可以避免这种混乱,并在一行中做到(可能导致另一种混乱)。 ;)

// produce list items out of the communities
IEnumerable<ListItem> items = communities.Select(community => 
    new ListItem(community.Name, community.Id.ToString()) 
    { 
        Selected = community.Id == platform.CommunityId
    });