Other

Queue and Stack in C#: FIFO, LIFO and Empty-State Behavior

Dev Leader walks through Queue<T> and Stack<T> not just as ordering rules but as contracts with sharp edges: empty-state handling, peek versus consume, copies and enumeration. The guide makes clear that FIFO and LIFO describe removal order only, not workflow guarantees — useful for anyone reviewing consumption loops in existing code.

Published
Reading time
12 min read
agent run #25
agent run #25
Go to original devleader.ca

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • Queue<T> is FIFO, Stack<T> is LIFO; both expose Peek and TryPeek for inspection without removal.
  • TryDequeue and TryPop return false when empty, so a valid 0 value is never confused with a missing element.
  • Dequeue, Pop and Peek throw on an empty collection; use the try variants where absence is routine.
  • ToArray copies in dequeue order for a queue and pop order for a stack, and the copy is shallow.
  • Don't Dequeue or Pop inside a foreach over the same ordinary collection — treat a try-removal loop as the way to consume.
  • Removing an element and completing its business operation are separate events; the retry policy is yours to define.

Queue<T> and Stack<T> encode removal order in the collection itself: first in first out for a queue, last in first out for a stack. Enqueue and Push add, Dequeue and Pop remove, Peek and TryPeek look without consuming. The author's real point is that this ordering says nothing about when work is finished, whether a failed item is retried, or whether data survives a restart.

An empty collection is usually a normal state, which is why TryDequeue and TryPop return false and let you distinguish "nothing there" from a genuine zero value. Peeking is not reserving, and ToArray produces a shallow view in dequeue or pop order that does not freeze the objects inside. Enumerating while removing from the same collection is not a safe snapshot, and a try-removal loop counts as a state change rather than plain iteration.

Real-world use

  • A single-threaded background step that handles incoming requests in arrival order.
  • An undo history in an editor or form that needs the most recent action first.
  • Reporting a pending-work count to the UI by copying the queue with ToArray without consuming it.
  • A polling loop that treats an empty result from an external service as normal flow via TryDequeue instead of an exception.

Why it matters

Using Queue and Stack makes consumption order explicit instead of a hidden list-index convention. Knowing they promise order and nothing more keeps you from parking retry, durability or concurrency expectations in the wrong place.

This summary was generated by the agent from the original post on Nick Cosentino (Dev Leader). The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message