You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现基于IEnumerable、IEnumerator的自定义Linked List及排查迭代异常

问题原因

  1. 核心错误是你把IEnumerable(可枚举集合)和IEnumerator(枚举器)的实现耦合在了同一个Lista类中:
    GetEnumerator()方法直接返回this,意味着所有遍历共享同一个Current状态。你在Add()方法中修改了Current使其指向链表最后一个节点,触发遍历时MoveNext()判断Current.nextRow为null直接返回false,所以foreach会立刻终止。
  2. 枚举逻辑不符合C#规范:标准枚举器初始位置在第一个元素之前,第一次调用MoveNext()才会指向首个元素,你的实现逻辑跳过了首个元素,且没有在返回枚举器前重置Current到表头。
  3. 你的猜想是正确的,this确实会返回当前类的可枚举实现,但因为枚举状态和集合自身状态绑定,才导致了遍历异常。

修复方案

方案1:临时快速修复(仅适合单线程无嵌套遍历场景)

仅修改GetEnumerator()方法,每次返回枚举器前先重置状态:

public IEnumerator GetEnumerator()
{
    Reset();
    return this;
}

该方案缺点是嵌套遍历或者多线程遍历同一链表时,状态会互相干扰,导致异常。

方案2:标准实现(推荐)

拆分独立枚举器类,每次遍历返回新的枚举器实例,状态完全隔离,同时修复Add方法的逻辑:

public class Lista : IEnumerable
{
    private Row _header;
    private int counter;

    public Lista()
    {
        _header = null;
        counter = 0;
    }

    public IEnumerator GetEnumerator()
    {
        return new ListaEnumerator(_header);
    }

    // 独立枚举器内部类
    private class ListaEnumerator : IEnumerator
    {
        private Row _current;
        private readonly Row _header;

        public ListaEnumerator(Row header)
        {
            _header = header;
            _current = null;
        }

        public bool MoveNext()
        {
            _current = _current == null ? _header : _current.nextRow;
            return _current != null;
        }

        public void Reset()
        {
            _current = null;
        }

        object IEnumerator.Current
        {
            get
            {
                if (_current == null)
                    throw new InvalidOperationException("枚举未启动或已结束");
                return _current;
            }
        }
    }

    public void Add(Reservation data)
    {
        Row newRow = new Row { reservation = data };
        if (counter == 0)
        {
            _header = newRow;
        }
        else
        {
            Row last = _header;
            while (last.nextRow != null)
                last = last.nextRow;
            last.nextRow = newRow;
        }
        counter++;
    }

    public Reservation GetReservation(int index)
    {
        int x = 0;
        foreach (Row row in this)
        {
            if (x == index)
                return row.reservation;
            x++;
        }
        return null;
    }

    public Reservation Remove(Reservation data)
    {
        if (_header == null) return null;
        Reservation reservation = null;
        if (_header.reservation.Equals(data))
        {
            reservation = _header.reservation;
            _header = _header.nextRow;
        }
        else
        {
            foreach (Row row in this)
            {
                if (row.nextRow != null && row.nextRow.reservation.Equals(data))
                {
                    reservation = row.nextRow.reservation;
                    row.nextRow = row.nextRow.nextRow;
                    break;
                }
            }
        }
        if (reservation != null)
            counter--;
        return reservation;
    }
}

额外修复了Remove方法的空引用风险,空链表直接返回,遍历中判断nextRow非空再访问。

内容的提问来源于stack exchange,提问作者Bruno Leitao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:24:03