Back to Blog
C#

C# LINQ Reverse: Reversing Sequences

c# linq reverse: Learn how LINQ Reverse() works in C#: its deferred execution behavior, buffering cost, and when to choose it over in-place reversal methods.

LINQC#IEnumerableDeferred ExecutionSequence Operations
Illustration of a horizontal row of numbered blocks being reversed in order, representing the C# LINQ Reverse method.

c# linq reverse requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

The LINQ Reverse() method returns a new sequence with elements in the opposite order. It is part of System.Linq and works on any IEnumerable<T>. The signature is:

public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source)

The method does not modify the original collection. Instead, it produces a new sequence that yields elements from the end to the beginning.

What LINQ Reverse() Actually Does

The Reverse() extension method is defined in the System.Linq namespace and extends IEnumerable<T>. When you call it, you get back an IEnumerable<T> that, when enumerated, produces the elements of the source sequence in reverse order.

using System.Linq; int[] numbers = { 1, 2, 3, 4, 5 }; var reversed = numbers.Reverse(); foreach (var number in reversed) { Console.WriteLine(number); } // Output: 5, 4, 3, 2, 1

The original numbers array remains unchanged. This is a key distinction from in-place reversal methods like Array.Reverse() or List<T>.Reverse(), which modify the underlying collection.

Reversing a List or Array

Both List<T> and arrays work directly with Reverse() because they implement IEnumerable<T>. The result is always a new IEnumerable<T> sequence.

List<string> names = new List<string> { "Alice", "Bob", "Carol" }; var reversedNames = names.Reverse(); Console.WriteLine(string.Join(", ", reversedNames)); // Output: Carol, Bob, Alice

If you need the result as a list or array, materialize it explicitly:

var reversedList = names.Reverse().ToList(); var reversedArray = names.Reverse().ToArray();

The ToList() and ToArray() calls force immediate evaluation. This matters when you need the data for multiple iterations or want to avoid re-enumerating the source.

Deferred Execution and Materialization

Reverse() uses deferred execution. The source sequence is not enumerated until you iterate over the result. This has an important consequence: the method must buffer the entire source sequence before it can yield the first reversed element.

Consider this:

IEnumerable<int> source = GetNumbers(); // some lazy sequence var reversed = source.Reverse(); // Nothing has been enumerated yet

When you start iterating reversed, the implementation first pulls every element from source and stores it in an internal buffer. Only after the source is exhausted can it start yielding elements from the buffer in reverse order.

This behavior differs from methods like Where() or Select(), which stream elements one at a time. Reverse() is a buffering operation, so its memory cost scales with the size of the source sequence.

Reversing Strings with LINQ

string implements IEnumerable<char>, so you can reverse a string with LINQ:

string text = "hello"; string reversed = new string(text.Reverse().ToArray()); // reversed = "olleh"

The Reverse() call produces an IEnumerable<char>, and the new string(...) constructor rebuilds a string from the reversed character sequence. This works, but for simple string reversal, a for loop or Array.Reverse() on a character array is usually more efficient because it avoids the LINQ overhead and intermediate allocations.

Reverse() vs In-Place Reversal Methods

ApproachModifies original?Returns new sequence?Best for
LINQ Reverse()NoYesImmutable pipelines, chaining with other LINQ operators
Array.Reverse()YesNoIn-place reversal of arrays
List<T>.Reverse()YesNoIn-place reversal of lists
Manual loopDependsDependsTight loops where allocation matters

Choose Reverse() when you are building a LINQ query pipeline and the original collection should stay untouched. Choose in-place methods when you own the collection, do not need the original order afterward, and want to avoid allocating a new sequence.

Performance and Memory Characteristics

The main cost of Reverse() is the internal buffering. For a sequence of n elements, the method allocates a buffer that holds all n items before yielding anything. This means:

  • Time complexity is O(n), since every element is visited exactly once.
  • Memory usage is O(n), because the entire sequence must be stored before the first reversed element can be produced.

For small in-memory collections like lists or arrays, this overhead is negligible. For large or lazily generated sequences, the buffering cost can be significant. If the source is a List<T> or array and you can tolerate modifying it, List<T>.Reverse() or Array.Reverse() avoids the allocation entirely.

There is also a subtle point about re-enumeration. If you iterate the reversed result multiple times, the source is enumerated and buffered again on each pass. Materializing the result with ToList() once and reusing that list avoids repeated buffering.

Common Mistakes and Edge Cases

One frequent mistake is expecting Reverse() to modify the original collection:

List<int> numbers = new List<int> { 1, 2, 3 }; numbers.Reverse(); // result is discarded, numbers is unchanged

The return value must be assigned or consumed. The original list still contains 1, 2, 3 in the original order.

Another edge case is calling Reverse() on an empty sequence. The method returns an empty sequence without throwing. A sequence with a single element returns a sequence with that same single element.

Null handling: Reverse() throws ArgumentNullException if the source is null, consistent with other LINQ operators.

When the source is a List<T> or array, the LINQ Reverse() implementation can use the IList<T> interface to access elements by index rather than enumerating, which is slightly faster. But the buffering behavior and the fact that it returns a new sequence remain the same.

c# linq reverse: Practical Usage and Code Examples | RYUSLOG DEV