在foreach循环中移除列表元素失败,多种Remove方法均无效求助
问题分析与解决方案
嘿,我一眼就瞅出你代码里的问题啦——你在foreach循环中直接修改正在遍历的集合,这可是C#集合操作里的经典坑!
为啥原来的代码删不掉元素?
foreach循环依赖于集合的枚举器,一旦枚举器创建完成,它就会“绑定”到当前集合的状态上。如果你在遍历过程中修改集合(比如调用Remove/RemoveAt),枚举器就会失效,要么直接抛出InvalidOperationException,要么就会出现你遇到的“元素看起来没被移除”的情况——因为枚举器没法同步集合的实时变化,遍历逻辑已经乱掉了。
而且你原来的代码里还绕了个大弯:先找Question的索引,再找QuestionValue,完全没必要,反而增加了不必要的性能开销。
两种靠谱的解决方案
方案1:先收集要删除的元素,再批量移除
这种方法最安全,先把所有需要删掉的QuestionValue都收集到一个临时列表里,等遍历完原集合再统一移除,完全不会干扰遍历过程:
// 第一步:收集所有没有权限的QuestionValue var valuesToRemove = new List<QuestionValue>(); foreach (Question q in questions) { foreach (QuestionValue qv in q.QuestionValueList) { // 用Any()替代Count() == 0,性能更优(找到匹配项就停止遍历) if (!m_User.OrganizationRole.QuestionValuePermissionList .Any(p => p.QuestionValue.QuestionValue_Id == qv.QuestionValue_Id)) { valuesToRemove.Add(qv); } } } // 第二步:批量移除收集到的元素 foreach (var qv in valuesToRemove) { // 找到该QuestionValue所属的Question var targetQuestion = questions.FirstOrDefault(q => q.QuestionValueList.Contains(qv)); if (targetQuestion != null) { targetQuestion.QuestionValueList.Remove(qv); } }
方案2:反向for循环遍历
如果你不想额外创建临时列表,可以用for循环从后往前遍历QuestionValueList。这样就算删除了当前元素,前面的元素索引不会受到影响,遍历逻辑依然正常:
foreach (Question q in questions) { // 从列表末尾开始遍历,避免删除元素后索引偏移 for (int i = q.QuestionValueList.Count - 1; i >= 0; i--) { QuestionValue qv = q.QuestionValueList[i]; if (!m_User.OrganizationRole.QuestionValuePermissionList .Any(p => p.QuestionValue.QuestionValue_Id == qv.QuestionValue_Id)) { q.QuestionValueList.RemoveAt(i); } } }
额外小优化
把Count() == 0改成!Any()是个好习惯——Count()会遍历整个集合统计数量,而Any()只要找到第一个匹配的元素就会停止,性能上会更高效,尤其是当权限列表比较大的时候。
内容的提问来源于stack exchange,提问作者Deniz Kılıç
相关产品推荐
相关产品推荐

