C# 堆栈和队列枚举顺序
我知道C# 堆栈和队列枚举顺序,c#,.net,C#,.net,我知道列表枚举器保证枚举顺序并尊重最后的排序操作,我知道字典和哈希集没有,也就是说,您可以不确保 Dictionary<string, string> dictionary = ...; foreach(var pair in dictionary) { } 字典=。。。; foreach(字典中的var对) { } 将按附加的顺序处理对 那么堆栈和队列呢?他们的枚举数保证任何顺序吗?是。它似乎没有明确的文档记录,但元素的枚举顺序与您弹出/退出队列的顺序相同。对于堆栈,枚举当
列表
枚举器保证枚举顺序并尊重最后的排序操作,我知道字典
和哈希集
没有,也就是说,您可以不确保
Dictionary<string, string> dictionary = ...;
foreach(var pair in dictionary)
{
}
字典=。。。;
foreach(字典中的var对)
{
}
将按附加的顺序处理对
那么
堆栈
和队列
呢?他们的枚举数保证任何顺序吗?是。它似乎没有明确的文档记录,但元素的枚举顺序与您弹出/退出队列的顺序相同。对于堆栈
,枚举当前由一个名为堆栈枚举器的嵌套私有类来完成(这来自):
注意它如何从设置为\u stack.\u size-1
的索引开始枚举,并递减索引以后进先出顺序返回每个元素
但是,由于这没有文档记录,您不能保证它始终是这样的(尽管Microsoft现在改变枚举器的工作方式是疯狂的!)
您可以检查嵌套的QueueEnumerator
类的实现,并类似地确定枚举是按照项目的出列顺序进行的
Stack.GetEnumerator()强烈暗示使用后进先出顺序。
如果您查看并检查所述输出,您可以看到它符合后进先出顺序
这强烈地表明微软完全打算按照后进先出的顺序枚举堆栈——但他们忘记(或懒得)明确地记录这一点 A是先进先出(FIFO)集合(文档中有这样的说法)。这意味着枚举器将按添加的顺序为您提供项
A是后进先出(LIFO)集合。这意味着枚举器按与添加方式相反的顺序提供项目
堆栈和队列是非常标准的计算机科学结构,因此如果没有严重的反弹,它们真的不能被重新使用。当您查看GetEnumerator()
函数的示例时,它清楚地记录了枚举顺序:
堆栈编号=新堆栈();
数字。推送(“一”);
数字。推送(“两”);
数字。推(“三”);
数字。推送(“四”);
数字。推(“五”);
//可以枚举堆栈而不干扰其内容。
foreach(数字中的字符串编号)
{
控制台写入线(编号);
}
/*此代码示例生成以下输出:
五
四
三
二
一
*/
队列编号=新队列();
编号。排队(“一”);
数字。排队(“两”);
数字。排队(“三”);
数字。排队(“四”);
数字。排队(“五”);
//可以枚举队列而不干扰其内容。
foreach(数字中的字符串编号)
{
控制台写入线(编号);
}
/*此代码示例生成以下输出:
一
二
三
四
五
*/
同样,对于基本的计算机科学定义,枚举器或迭代器必须按照集合的自然顺序表示元素。特定集合类型具有已定义的顺序
警告
请注意,虽然枚举过程确实反映了FIFO和LIFO集合()的自然顺序,但这不是队列()和堆栈()的用途。它们用于Enqueue()
/Dequeue()
和Push()
/Pop()
/Peek()
交互。Microsoft包含枚举器以使所有内容与基本ICollection
界面保持一致,并使枚举器保持集合的自然顺序
队列的目的是提供可以按顺序处理的工作管道。堆栈的目的是提供一种在本地工作完成时返回到以前上下文的方法。他们打算一次处理一个项目。使用枚举器对集合进行迭代是一种附加步骤,它只用于整个目的,不会从队列/堆栈中移除项。本质上,这是对所有物品的一次窥视。是否有任何证据证明这一点?@ZverevEugene,刚刚查看了MSDN,似乎没有提及它。@MatthewWatson确实;它只是没有明确说明它会影响枚举顺序。参考源是实现细节,而不是文档。@LasseV.Karlsen我同意这不是文档——要知道微软是否打算永远不改变这种行为,唯一的方法就是让他们记录下来。然而,他们现在改变工作方式的可能性几乎为零。你正在比较不同的东西。堆栈、队列、数组、列表具有强大的排序保证,而字典则没有。你遇到过具体的问题吗?我找到了@PanagiotisKanavos不,我没有。但这无关紧要。说实话,几年来我一直在使用字典
枚举,代码的构建依赖于枚举顺序,非常糟糕。当字典
改变枚举顺序时,我从未遇到过这样的情况。“这并不会让错误变得更可怕。”马修沃森谢谢你的提示。很近,但还不够近。我需要一个有文件证明的顺序,以确保枚举。仅仅观察是不好的。RE:dictionares:字典唯一可能改变顺序的时间是当字典
调整大小时。枚举未定义的原因是它处于内部哈希顺序(GetHashCode()被进一步哈希到有限数量的bucket中)。我认为这里的问题与没有明确记录枚举器的行为有关。当然可以,.Push()
,.Pop()
private class StackEnumerator : IEnumerator, ICloneable
{
private Stack _stack;
private int _index;
private int _version;
private Object currentElement;
internal StackEnumerator(Stack stack) {
_stack = stack;
_version = _stack._version;
_index = -2;
currentElement = null;
}
public Object Clone()
{
return MemberwiseClone();
}
public virtual bool MoveNext() {
bool retval;
if (_version != _stack._version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
if (_index == -2) { // First call to enumerator.
_index = _stack._size-1;
retval = ( _index >= 0);
if (retval)
currentElement = _stack._array[_index];
return retval;
}
if (_index == -1) { // End of enumeration.
return false;
}
retval = (--_index >= 0);
if (retval)
currentElement = _stack._array[_index];
else
currentElement = null;
return retval;
}
public virtual Object Current {
get {
if (_index == -2) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
if (_index == -1) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
return currentElement;
}
}
public virtual void Reset() {
if (_version != _stack._version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
_index = -2;
currentElement = null;
}
}
Stack<string> numbers = new Stack<string>();
numbers.Push("one");
numbers.Push("two");
numbers.Push("three");
numbers.Push("four");
numbers.Push("five");
// A stack can be enumerated without disturbing its contents.
foreach( string number in numbers )
{
Console.WriteLine(number);
}
/* This code example produces the following output:
five
four
three
two
one
*/
Queue<string> numbers = new Queue<string>();
numbers.Enqueue("one");
numbers.Enqueue("two");
numbers.Enqueue("three");
numbers.Enqueue("four");
numbers.Enqueue("five");
// A queue can be enumerated without disturbing its contents.
foreach( string number in numbers )
{
Console.WriteLine(number);
}
/* This code example produces the following output:
one
two
three
four
five
*/