Back to Blog
C#

C# Stack.TryPeek: Safe Peek Without Exceptions

Learn how C# Stack<T>.TryPeek inspects the top element without throwing on an empty stack, with code examples and edge cases.

C#Stack.NETCollectionsTryPeek
Illustration of a stack data structure with a TryPeek operation returning a boolean and the top element.

Stack<T>.TryPeek lets you inspect the top element of a stack without throwing an exception when the stack is empty. It returns true and assigns the top element to an out parameter on success; when the stack is empty, it returns false and sets the parameter to default(T). This makes the empty check and the peek one method call instead of a separate Count check.

The Problem TryPeek Solves

Consider a typical peek operation:

var stack = new Stack<int>(); stack.Push(10); if (stack.Count > 0) { int top = stack.Peek(); Console.WriteLine(top); }

The Count > 0 check is necessary because Peek throws an InvalidOperationException on an empty stack. This pattern is safe in single-threaded code, but it is verbose and leaves room for mistakes. If you forget the check, you get an exception. If another thread modifies the stack between the check and the peek, the behavior of the collection is not guaranteed. TryPeek removes the need for the explicit check and makes the intent clearer.

Syntax and Return Value

TryPeek is defined on Stack<T> with the following signature:

public bool TryPeek(out T result)

It returns true if the stack is not empty, and in that case result contains the top element. If the stack is empty, it returns false and sets result to the default value of T (default(T)). The method does not modify the stack.

A Minimal Example

Here is a complete example that shows the behavior for both non-empty and empty stacks:

using System; using System.Collections.Generic; var stack = new Stack<string>(); stack.Push("first"); stack.Push("second"); if (stack.TryPeek(out string top)) { Console.WriteLine($"Top element: {top}"); } else { Console.WriteLine("Stack is empty."); } stack.Clear(); if (stack.TryPeek(out string emptyTop)) { Console.WriteLine($"Top element: {emptyTop}"); } else { Console.WriteLine("Stack is empty."); Console.WriteLine($"Default value: {emptyTop ?? "null"}"); }

The first TryPeek call returns true and top becomes "second". After clearing the stack, the second call returns false and emptyTop is null because string is a reference type. For value types, result would be default(T), which is 0 for numeric types and false for booleans.

TryPeek vs Peek vs Count

The following table summarizes the differences between the three common ways to inspect the top of a stack:

ApproachThrows on empty?Returns top?Combines check and read?
Peek()YesYesYes
Count > 0 + Peek()No, if checkedYesNo
TryPeek(out T)NoYes (via out)Yes

Peek is simple but throws on an empty stack. The Count + Peek pattern avoids the exception only if you remember the check, but it is not a combined operation; another thread could modify the stack between the two calls. TryPeek performs the check and read in one method call, so it is a better fit when an empty stack is an expected condition. As with any non-thread-safe collection, concurrent modifications still require external synchronization.

Handling the Default Value in the out Parameter

When TryPeek returns false, the out parameter receives default(T). For reference types, this is null. For value types, it is the zero value. This matters when you want to distinguish between a valid element and an empty stack.

Consider a stack of nullable integers:

var stack = new Stack<int?>(); stack.Push(42); if (stack.TryPeek(out int? value)) { Console.WriteLine(value); // 42 } stack.Pop(); if (stack.TryPeek(out int? emptyValue)) { Console.WriteLine(emptyValue); } else { Console.WriteLine("Stack is empty."); Console.WriteLine($"emptyValue is {emptyValue?.ToString() ?? "null"}"); }

Here, int? is a nullable value type, so default(int?) is null. The out parameter receives null when the stack is empty. If you were using a non-nullable int, the out parameter would be 0, which could be mistaken for a valid element. Always check the boolean return value before using the out parameter.

Common Mistakes and Edge Cases

One common mistake is ignoring the return value of TryPeek and using the out parameter unconditionally. This can lead to using a default value when the stack is empty, which may produce incorrect logic.

Another edge case is using TryPeek on a stack that is modified concurrently. TryPeek is a single method call, but it does not lock the stack or prevent other threads from pushing or popping elements. Stack<T> is not thread-safe, so concurrent use requires external synchronization. If you need a consistent snapshot of the stack, synchronize access to the stack before calling methods on it.

Note that TryPeek applies to Stack<T>. Queue<T> also has a similar TryPeek in current .NET versions, but this article focuses on the stack version.

Performance and Allocation Considerations

TryPeek is an O(1) operation. It does not allocate a new object for the out parameter; the variable already exists at the call site. In contrast, the Count > 0 + Peek pattern involves two separate calls, but both are also O(1). The main difference is not raw speed but the number of operations and the potential for exceptions. In hot paths, avoiding an exception is beneficial because exceptions are expensive. TryPeek eliminates the exception path entirely.

There is a subtle allocation consideration when T is a reference type and you use the out parameter: the variable you pass already exists, so no new allocation occurs. For value types, the value is copied into the variable, which is the same as with Peek.

When to Use TryPeek Over Other Approaches

Use TryPeek when you need to inspect the top element and handle the empty case gracefully. This is common in algorithms that process stacks iteratively, such as parsing or backtracking. It is also preferred when a separate Count check could be racy.

If you know the stack is never empty in a particular code path, Peek is simpler and more direct. If you need to remove the element after inspecting it, TryPop is the analogous method for popping without throwing.

The decision comes down to whether an empty stack is an expected condition. If it is, TryPeek is the cleanest and safest option. If it is a programming error, Peek will surface the bug with an exception, which may be desirable.

C# Stack<T>.TryPeek: Inspect the Top Element Without Exceptions | RYUSLOG DEV