如何为自定义泛型Stack<T>实现符合NUnit测试要求的GetEnumerator()方法?
解决自定义泛型Stack迭代时修改未抛出异常的问题
你的问题核心在于当前的迭代器没有检测集合在迭代过程中被修改的逻辑,原来的null检查完全起不到作用——毕竟迭代时stack字段根本不会变成null,你需要模仿.NET内置集合的版本号检测机制来实现这个需求。
问题根源分析
你现在的GetEnumerator()方法里的if (this.stack == null)判断永远不会触发,因为迭代过程中stack实例始终存在。而.NET内置的集合(比如List<T>)之所以能在迭代时检测到修改并抛出异常,是因为它们维护了一个内部版本号:每次集合结构变化(添加、删除元素)时版本号递增,迭代器会记录初始版本号,每次迭代时对比版本号,不一致就抛出异常。你的Stack类完全没做这个检测,所以测试无法通过。
修改方案
我们需要给Stack类添加版本号字段,在Push/Pop修改集合时更新版本号,然后在迭代器中实时检查版本号是否变化:
1. 添加版本号字段
在你的Stack类中新增一个私有字段:
private int _version = 0;
2. 更新Push和Pop方法
每次修改集合时递增版本号:
public void Push(T item) { this.stack.Add(item); _version++; // 集合结构变化,更新版本号 } public T Pop() { if (this.stack.Count == 0) { throw new InvalidOperationException("Invalid operation pop, stack is empty."); } T value = this.stack[this.stack.Count - 1]; this.stack.RemoveAt(this.stack.Count - 1); _version++; // 集合结构变化,更新版本号 return value; }
3. 重写GetEnumerator方法
在迭代器中捕获初始版本号,每次迭代前检查版本是否一致:
public IEnumerator<T> GetEnumerator() { int currentVersion = _version; // 记录迭代开始时的版本号 for (int index = this.stack.Count - 1; index >= 0; index--) { // 每次返回元素前检查集合是否被修改 if (currentVersion != _version) { throw new InvalidOperationException("Stack cannot be changed during iteration."); } yield return this.stack[index]; } } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
为什么这样能通过测试?
现在当你在foreach循环中调用Push或Pop时,_version会立即递增,下一次迭代时currentVersion和_version就会不一致,触发你期望的InvalidOperationException,完美匹配测试用例的要求。
另外补充一点:你的Push和Pop方法本身的逻辑是没问题的,核心问题完全出在迭代器的修改检测上。
内容的提问来源于stack exchange,提问作者user17825851
相关产品推荐
相关产品推荐

