Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 堆栈和队列枚举顺序_C#_.net - Fatal编程技术网

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

    */