C#集合遍历时安全增删元素的方法
C# 集合不支持在遍历过程中直接增加或删除元素。本文将分析此限制的成因,并提供基于 LinkedList<>、List<> 和自定义链表的三种安全实现方案。
结果与背景
当处理如用户生命周期(出生与死亡)这类动态变化的集合时,需要在遍历的同时执行增删操作。由于 C# 的 foreach 机制依赖快照或迭代器状态追踪,集合结构变化会导致 InvalidOperationException。为解决此问题,以下提供三种不同数据结构的应对策略。
第一种方法:使用 LinkedList<> 锁定终点
利用双链表特性,在遍历前获取原链表的尾节点作为结束标记,并在循环末端追加新元素。注意在删除当前节点后,需提前获取下一个节点的引用,以免指针丢失。
using System;
using System.Collections.Generic;
namespace CollectionUpdateExample
{
public class Program
{
// 初始化,添加0-29的整数进入链表
private void Init(LinkedList list)
{
for (int i = 0; i < 30; i++)
{
list.AddLast(i);
}
}
// 遍历并进行增删逻辑
public void Process(LinkedList list)
{
// 记录遍历起始节点与原始末尾节点
LinkedListNode nodeNow = list.First;
LinkedListNode nodeLast = list.Last;
LinkedListNode nodeTmp;
// 循环直到达到原始链表的最后一个元素
while (nodeNow != null && nodeNow != nodeLast)
{
// 满足被3整除条件,在链表尾部追加一个0元素
if (nodeNow.Value % 3 == 0)
{
list.AddLast(0);
}
// 满足被2整除条件,移除该元素
if (nodeNow.Value % 2 == 0)
{
// 先缓存下一个节点,再删除当前节点
nodeTmp = nodeNow.Next;
list.Remove(nodeNow);
// 移动指针到下一位置
nodeNow = nodeTmp;
}
else
{
// 否则正常移动到下一个节点
nodeNow = nodeNow.Next;
}
}
// 最后单独处理原始链表的尾节点
if (nodeNow != null)
{
if (nodeNow.Value % 3 == 0) list.AddLast(0);
if (nodeNow.Value % 2 == 0) list.Remove(nodeNow);
}
}
}
}
第二种方法:使用 List<> 标记尾部
List<> 是基于数组的顺序表,虽然增删操作的时间复杂度较高(涉及内存移动),但仍可通过维护一个索引指针来解决遍历冲突。核心思路是记录初始容量下的尾部边界,遇到新增元素时在边界外进行;删除元素时则无需额外处理,只需保证循环范围不覆盖新增部分即可。
代码实现上需注意:因数组空间连续性,频繁增删性能较差。若集合规模较大,建议优先考虑链表方案;若需随机访问且变动较少,可尝试将符合条件的元素提取至临时列表,遍历结束后统一调用 RemoveRange 或 AddRange。
第三种方法:自定义单链表支持合并
标准的 LinkedList<> 出于防止环状结构(Loop)及保护 Last、Count 属性准确性的考虑,不支持直接将另一个链表的节点接入自身。若要高效合并两个集合,需自定义泛型链表类:
// 伪代码示意:合并两个链表的核心原理
Node current = list.Head;
while(current.Next != null)
current = current.Next;
current.Next = list2.Head;
此类设计允许灵活拼接节点,避免了额外的空间分配与深拷贝开销。但需自行管理遍历过程中的边界判定,以确保逻辑闭环。
完成判断与总结
验证遍历成功的方法是检查最终集合元素是否符合既定的数值规则(如模运算过滤后的剩余值及追加值的数量)。上述方法规避了修改正在迭代的集合带来的系统崩溃。以上就是C#集合遍历时增删元素方法的详细内容,更多关于C#数据处理技巧的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









