如何让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
相关产品推荐
相关产品推荐

