如果队列为空,Queue.Peek会抛出InvalidOperationException异常。

7
我是一名有用的助手,可以为您翻译文本。

我有一个简单的队列来管理添加到我的应用程序中的项目。

从微软当前的Queue.Peek方法文档中:

screenshot

如果使用Peek()仍然会抛出无效操作异常,那么使用Peek()有什么意义?

我认为使用Peek()的整个目的是使代码不生成异常。

2个回答

12

即使MSDN也提到了原因:

可以将 null 作为值添加到队列中,要区分 null 值和队列结尾,检查 Count 属性或捕获 InvalidOperationException。当队列为空时引发该异常。

所以,如果你尝试查看第一个元素,队列抛出异常的原因是它可能是null。那么如何区分有效的null值和没有项?

如果队列包含像int这样的值类型,也是同样的问题。如果没有元素可以查看,它应该返回-1吗?不,-1可能是一个有效值,因此你无法知道队列中是否有另一个元素。

相反,请使用Count属性来检查队列是否为空:

var queue = new Queue<int>();
queue.Enqueue(-1);
while (queue.Count > 0)
{
    int current = queue.Peek();         // still in the queue
    Console.WriteLine(queue.Dequeue()); // now empty
}

我认为你可能将queue.Peek和像dataReader.Read这样的方法混淆了。它们之间的区别在于Read会将读取器前进到下一条记录,并返回一个指示是否存在记录的bool。而Queue.Peek也会返回该“记录”,但其目的不同,因此如果要知道是否有记录,请勿使用Peek

顺便说一下,这种行为在框架中是一致的。其他方法如Enumerable.First在对空序列使用时也会抛出InvalidOperationException异常。


它似乎只是像使用Peek()的其他所有东西一样,当没有其他内容时返回-1或null。那么Peek()有什么意义呢?只需调用Dequeue并在那里捕获异常即可。 - user153923
@jp2code:为什么Peek要返回-1呢?它应该返回队列中的第一个项目。Queue<T>可以存储任何东西,不仅仅是像int这样的值类型。而且,即使它包含整数,-1也可能是一个有效的数字,所以你不知道这是第一个/最后一个还是其他。对于null也是同样的情况。抛出异常是提示您逻辑有问题。您正在请求另一个项目,但没有任何项目可用。使用while(myQueue.Count > 0){ // 在这里可以查看 } - Tim Schmelter

4
Peek的作用是查看队列的下一个元素,而不将其删除。它没有被删除这一点是PeekPop(在.NET中为Dequeue)之间的主要区别。(这与.NET无关;对于任何语言的队列结构,如果有一个返回弹出值的Pop(/Dequeue),那么这就是这两者之间的区别。
如果队列为空,Queue无法返回任何合理的内容。抛出异常是唯一的替代方案,所以这是适当的行为。要么捕获并处理异常,要么(如果您不担心竞态条件)在调用Peek/Dequeue之前检查队列是否为空。

我仍然不明白为什么要使用Peek()。Peek()的目的是查看队列中是否还有剩余项,但如果没有任何内容,则会抛出异常。如果没有编写异常处理程序,那么有人如何编写使用Peek()的代码呢?我的意思是,为什么不尝试/捕获Pop或Dequeue?显然我错过了这个原因。希望有人能启发我。 - user153923
如果你使用了 Dequeue(),那么它会改变队列,这不是你想要的。Peek() 返回下一个元素,而不会 改变队列。 - Sneftel
@jp2code 如果要确保不会抛出异常,只需在Count为零时不调用它即可。但根据编程风格,您可能更喜欢捕获异常而不是显式检查计数。 - Sneftel
jp2code,你的说法“Peek()的目的是查看队列中是否还有未使用的内容”并不完全正确。很可能你想要检查队列中下一个对象的属性,例如,看看是否要立即处理或等待一段时间,或在处理之前采取其他操作。 - dhochee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接