我一直在努力解决这个问题。我试图使CustomStack像Stack一样,只实现Push(T)、Pop()、Peek()和Clear()方法。我有这段代码,我认为它是正确的,但输出只显示了一半的数字。我认为这与推送法有关,但我看不出它有什么问题。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
namespace Enumerator
{
class Program
{
static void Main(string[] args)
{
CustomStack<int> collection = new CustomStack<int>();
for (int i = 0; i < 30; i++)
{
collection.Push(i);
Console.WriteLine(collection.Peek());
}
collection.Push(23);
foreach (int x in collection)
{
Console.WriteLine(collection.Pop());
}
Console.WriteLine("current", collection.Peek());
Console.ReadKey();
}
}
public class CustomStack<T> : IEnumerable<T>
{
private T[] arr;
private int count;
public CustomStack()
{
count = 0;
arr = new T[5];
}
public T Pop()
{
int popIndex = count;
if (count > 0)
{
count--;
return arr[popIndex];
}
else
{
return arr[count];
}
}
public void Push(T item)
{
count++;
if (count == arr.Length)
{
Array.Resize(ref arr, arr.Length + 1);
}
arr[count] = item;
}
public void Clear()
{
count = 0;
}
public T Peek()
{
return arr[count];
}
public int Count
{
get
{
return count;
}
}
public IEnumerator<T> GetEnumerator()
{
return new MyEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new MyEnumerator(this);
}
public class MyEnumerator : IEnumerator<T>
{
private int position;
private CustomStack<T> stack;
public MyEnumerator(CustomStack<T> stack)
{
this.stack = stack;
position = -1;
}
public void Dispose()
{
}
public void Reset()
{
position = -1;
}
public bool MoveNext()
{
position++;
return position < stack.Count;
}
Object IEnumerator.Current
{
get
{
return stack.arr[position];
}
}
public T Current
{
get
{
return stack.arr[position];
}
}
}
}
}
发布于 2013-05-10 22:23:42
您正在做一些要求您永远不要做的事情:在使用枚举数迭代集合时,您正在修改集合。( foreach
循环是分配枚举数的语法糖。)
IEnumerable
的文档实际上表明,如果您的数据结构在被枚举时被修改,像您这样的实现会抛出异常。(尝试使用List<T>
,您将看到;如果在foreach
中枚举列表时添加或删除项,则列表将抛出。)
这就是造成问题的原因;您的数据结构的设计不是(1)在滥用时抛出,也不是(2)在被滥用时表现良好,因此当您滥用它时,它表现得很糟糕。
我的建议是:如果你那样做会很伤人,那就别那么做。不要在枚举集合的循环中修改集合。
相反,创建一个IsEmpty
属性并编写您的循环:
while(!collection.IsEmpty)
Console.WriteLine(collection.Pop());
这样,在同时处理枚举数时,就不会修改集合。
这里的具体问题是:每次循环时,position
总是在增加。count
一直在下降。你说只有一半的物品被清点。那就算了吧。如果你有十个项目,位置从零开始,直到它大于计数,然后每次通过循环.
position count
0 10
1 9
2 8
3 7
4 6
5 5
我们完成了,我们只列举了一半的项目。
如果您想让您的集合在迭代时被修改时保持健壮,那么当堆栈被推送或弹出时,position
必须更改。每一次都不能盲目地增加,即使计数在变。找出正确的行为是非常棘手的,这就是为什么文档建议您直接抛出。
如果要使集合在被枚举时修改时抛出异常,诀窍是使对象具有一个名为“版本号”的int。每次推送或弹出集合时,请更改版本号。然后让迭代器在迭代开始时获取版本号的副本;如果它检测到当前版本号与副本不同,则集合在枚举期间已被修改,您可以抛出一个集合修改的异常。
谢谢这个有趣的问题;我可能会在我的博客中使用它作为一个例子,并可能看我是否可以编写一个静态分析器来检测这种危险的修改。
https://stackoverflow.com/questions/16494395
复制相似问题