Back to Blog
C#

C# LINQ Append and Prepend: Adding Elements to Sequences

c# linq append prepend: Understand C# LINQ Append and Prepend: their deferred execution behavior, chaining patterns, performance tradeoffs, and when to prefer Concat o...

LINQC#IEnumerableDeferred ExecutionSequence Operations
Illustration of a horizontal sequence of blocks with one element added at the start and one at the end, representing LINQ Append and Prepend

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

What Append and Prepend Do

Append and Prepend are LINQ extension methods that return a new sequence with one additional element. Append places the element at the end of the sequence; Prepend places it at the beginning. Both methods are defined in the System.Linq namespace and work with any IEnumerable<T>.

using System.Linq; int[] numbers = { 2, 3, 4 }; IEnumerable<int> withStart = numbers.Prepend(1); IEnumerable<int> withEnd = numbers.Append(5); Console.WriteLine(string.Join(", ", withStart)); // 1, 2, 3, 4 Console.WriteLine(string.Join(", ", withEnd)); // 2, 3, 4, 5

The original numbers array is untouched. Both methods return a new IEnumerable<int> that yields the combined sequence when enumerated.

Deferred Execution: The Original Sequence Is Never Modified

Append and Prepend use deferred execution. The returned sequence does not contain a snapshot of the source. Instead, it holds a reference to the source and the extra element, and it performs the combination only when you enumerate it.

var source = new List<int> { 1, 2, 3 }; var extended = source.Append(4); source.Add(5); foreach (var item in extended) { Console.WriteLine(item); // 1, 2, 3, 5, 4 }

Because extended is enumerated after 5 is added to source, the output includes 5 before the appended 4. This is the same lazy behavior you see with Select and Where. If you need a stable snapshot, materialize the result with ToList() or ToArray() at the point where the source is in the state you want.

Chaining Append and Prepend Calls

You can chain multiple calls to build a sequence with elements on both ends.

var middle = new[] { 3, 4, 5 }; var result = middle .Prepend(2) .Prepend(1) .Append(6) .Append(7); Console.WriteLine(string.Join(", ", result)); // 1, 2, 3, 4, 5, 6, 7

Each call wraps the previous sequence in a new iterator. The order of the prepended elements is determined by the order of the calls: the first Prepend places 2 before the original sequence, and the second places 1 before that. Appends accumulate in call order, so 6 comes before 7.

This chaining is readable for a small number of elements. If you find yourself writing more than a few consecutive Append or Prepend calls, consider whether a different construction would be clearer.

Append and Prepend vs. Concat and List Building

Append and Prepend each add exactly one element. When you need to add several elements, Concat is often a better fit because it combines two sequences.

int[] baseNumbers = { 3, 4, 5 }; int[] leading = { 1, 2 }; int[] trailing = { 6, 7 }; var combined = leading.Concat(baseNumbers).Concat(trailing);

The Concat approach keeps the added elements in a collection, which is easier to manage when the number of elements is dynamic or comes from another source. It also avoids the nested iterator structure that results from many individual Append calls.

If your goal is a materialized List<T> that you will keep modifying, building the list directly is more appropriate:

var list = new List<int> { 3, 4, 5 }; list.Insert(0, 1); // prepend list.Add(6); // append

Append and Prepend are the right choice when you want to keep the result as an IEnumerable<T> and avoid mutating an existing collection.

Performance and Allocation Characteristics

Each Append or Prepend call allocates a new iterator object. The source sequence is not copied, so the memory cost is proportional to the number of calls, not the number of elements. For a single element, this is negligible.

The situation changes when you chain many calls. Ten Append calls create ten nested iterators. Enumerating the result walks through all ten layers, and each layer adds a small amount of overhead per element. For a few calls this is irrelevant; for dozens of calls on a large sequence, the overhead becomes measurable.

Prepend has a slightly different enumeration pattern than Append. To yield the prepended element first, the iterator must yield that element before starting to enumerate the source. With Append, the source is enumerated first and the extra element comes last. Both have the same allocation profile, but the enumeration order differs.

When you need to add many elements, prefer Concat with a collection, or build the final sequence with a List<T> and convert it once. This keeps the iterator chain shallow and the code easier to reason about.

Edge Cases: Null Sources, Null Elements, and Empty Sequences

Append and Prepend throw ArgumentNullException if the source sequence is null. The check happens when the method is called, not when the result is enumerated.

IEnumerable<int>? source = null; var result = source.Append(1); // throws ArgumentNullException

Adding a null element is allowed for reference types. Append(null) simply adds null to the sequence, and the result remains a valid IEnumerable<T>.

Empty sequences work as expected. Enumerable.Empty<int>().Append(1) yields a single element, and Enumerable.Empty<int>().Prepend(1) yields the same single element. There is no special handling needed for the empty case.

When to Reach for Append and Prepend

Use Append and Prepend when you need to add a single element to a sequence without modifying the original collection and without materializing the result. They fit naturally into LINQ pipelines where the result stays lazy.

Avoid them when you are adding many elements, when you need a mutable collection, or when the source sequence changes between the call and the enumeration and you want a stable snapshot. In those cases, Concat, List<T>, or an immediate ToList() is the clearer choice.

The methods are also limited to method syntax. You cannot express Append or Prepend in LINQ query syntax, so they appear only in fluent chains. This is consistent with their role as small utilities for adjusting the boundaries of a sequence.

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