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

如何让foreach使用泛型IEnumerator<T>遍历C#自定义集合?

解决自定义链表foreach遍历获取值而非节点的问题

问题根源

你当前的MyLinkedList<T>中,泛型版本的GetEnumerator()是显式接口实现(即IEnumerable<T?>.GetEnumerator()),而非泛型的GetEnumerator()是类的公共成员。C#的foreach语句在编译时会优先选择类的公共非泛型方法,而非显式实现的泛型接口方法,因此遍历得到的是MyLinkedListNode<T>实例而非预期的T类型值。

修复步骤

1. 调整集合类的枚举器实现

将泛型的GetEnumerator()改为公共方法,同时让非泛型的接口实现调用这个泛型方法。这样foreach会优先识别并调用泛型版本,因为它提供了更明确的类型信息:

public class MyLinkedList<T> : IEnumerable<T?> where T : IEquatable<T?>
{
    // 为简化已移除其他方法

    // 公共泛型枚举器方法,foreach优先调用此方法
    public IEnumerator<T?> GetEnumerator()
        => new MyLinkedListNodeEnumerator<T>(_root);

    // 显式实现非泛型接口,复用泛型枚举器
    IEnumerator IEnumerable.GetEnumerator()
        => GetEnumerator();
}

2. 修正枚举器的逻辑错误

你当前的MyLinkedListNodeEnumerator<T>实现违反了枚举器的规范:Current属性不应该修改枚举器的位置,移动操作应该由MoveNext()负责。原实现会导致遍历行为异常(比如跳过元素、重复获取等),以下是修正后的枚举器代码:

public class MyLinkedListNodeEnumerator<T>(MyLinkedListNode<T>? root) 
    : IEnumerator<T?> where T : IEquatable<T?>
{
    private readonly MyLinkedListNode<T>? _root = root;
    private MyLinkedListNode<T>? _current; // 初始为null,表示在第一个元素之前
    private bool _disposed;

    // 泛型Current,返回当前节点的数据
    public T? Current
    {
        get
        {
            EnsureNotDisposed();
            if (_current == null)
                throw new InvalidOperationException("枚举器未处于有效位置,请先调用MoveNext()");
            return _current.Data;
        }
    }

    // 非泛型Current,复用泛型实现
    object? IEnumerator.Current => Current;

    // 移动到下一个元素,返回是否存在有效元素
    public bool MoveNext()
    {
        EnsureNotDisposed();
        _current = _current == null ? _root : _current.Next;
        return _current != null;
    }

    // 重置枚举器到初始状态
    public void Reset()
    {
        EnsureNotDisposed();
        _current = null;
    }

    // 释放资源
    public void Dispose()
    {
        _disposed = true;
        _current = null;
    }

    private void EnsureNotDisposed()
    {
        if (_disposed)
            throw new ObjectDisposedException(nameof(MyLinkedListNodeEnumerator<T>));
    }
}

验证遍历效果

现在使用foreach遍历集合时,会正确获取T类型的值:

var list = new MyLinkedList<int>();
list.InsertFirst(10);
list.InsertNext(20);
list.InsertNext(30);

foreach (int num in list)
{
    Console.WriteLine(num); // 输出10、20、30
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:55:28