我知道List
枚举器保证枚举顺序并尊重最后一次排序操作,我知道Dictionary
和HashSet
不是,即你可以不确保
Dictionary<string, string> dictionary = ...;
foreach(var pair in dictionary)
{
}
将按照附加顺序处理对。
Stack
和Queue
怎么样?他们的调查员是否保证任何订单?
答案 0 :(得分:9)
对于Stack
,枚举当前由一个名为StackEnumerator
的嵌套私有类完成(这来自Reference Source):
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._size-1
开始,并递减索引以返回LIFO顺序中的每个元素。
但是,因为没有记录,你不能保证它总是这样(虽然微软改变枚举器现在的工作方式会很疯狂!)
您可以检查嵌套QueueEnumerator
类的实现,同样确定枚举是按照项目出列的顺序完成的。
Stack.GetEnumerator()强烈暗示使用了LIFO订单。
如果查看the example for Stack<T>.GetEnumerator()
in Microsoft's documentation并检查所述输出,您可以看到它是LIFO顺序。
这强烈暗示微软完全打算以LIFO顺序枚举一个堆栈 - 但是他们忘记了(或者没有理由)明确记录这个!
答案 1 :(得分:6)
Queue是先进先出(FIFO)集合(在文档中正确说明)。这意味着枚举器按照添加顺序为您提供项目。
Stack是一个后进先出(LIFO)集合。这意味着枚举器以与添加方式相反的顺序为您提供项目。
堆栈和队列是非常标准的计算机科学构造,因此如果没有严重的反弹,它们真的无法重新定位。当您查看GetEnumerator()
函数的示例时,它会清楚地记录枚举的顺序:
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
*/
同样,对于基本的计算机科学定义,枚举器或迭代器必须以集合的自然顺序呈现元素。特定的集合类型具有已定义的顺序。
<强>买者强>
请注意,虽然枚举过程确实反映了FIFO和LIFO集合(ref)的自然顺序,但这不是队列(ref)和堆栈(ref)的方式是打算使用。它们旨在与Enqueue()
/ Dequeue()
和Push()
/ Pop()
/ Peek()
互动使用。 Microsoft包含枚举器以使所有内容与基本ICollection<T>
接口保持一致,并使枚举器保持在集合的自然顺序中。
队列的目的是提供可以按顺序处理的工作流程。 Stack的目的是提供一种在本地工作完成时返回到先前上下文的方法。它们旨在一次处理一个项目。使用枚举器类整个集合迭代整个目的并且不从队列/堆栈中删除项目。它基本上是对所有物品的窥视。
答案 2 :(得分:1)
是。它似乎没有明确记录,但元素的枚举顺序与弹出/出列的顺序相同。