Accessing elements from the end of a collection or extracting a slice required verbose calculations or LINQ methods. This was especially cumbersome when working with the last few elements or specific ranges.
C# 8.0 introduces ranges and indices with two new operators: ^
for indexing from the end and ..
for creating ranges. These operators provide a concise, readable syntax for slicing collections and are particularly powerful when combined with Span<T>
and Memory<T>
for high-performance scenarios.
Code
C#
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int lastItem = numbers[^1]; // 10
int secondToLast = numbers[^2]; // 9
int[] firstThree = numbers[..3]; // { 1, 2, 3 }
int[] lastThree = numbers[^3..]; // { 8, 9, 10 }
int[] middle = numbers[3..7]; // { 4, 5, 6, 7 }
int[] allButFirstAndLast = numbers[1..^1]; // { 2, 3, 4, 5, 6, 7, 8, 9 }
// Can also store ranges in variables
Range middleRange = 3..7;
int[] subset = numbers[middleRange];
C#
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int lastItem = numbers[numbers.Length - 1];
int secondToLast = numbers[numbers.Length - 2];
int[] firstThree = numbers.Take(3).ToArray();
int[] lastThree = numbers.Skip(numbers.Length - 3).ToArray();
int[] middle = numbers.Skip(3).Take(4).ToArray();
int[] allButFirstAndLast = numbers.Skip(1).Take(numbers.Length - 2).ToArray();
Notes
- The
^
operator creates anIndex
from the end:^1
is the last element,^2
is second-to-last, etc. - The
..
operator creates aRange
: the start is inclusive, the end is exclusive - Omitting the start (
..3
) means "from the beginning", omitting the end (3..
) means "to the end" - Works with arrays, strings,
Span<T>
,Memory<T>
, and any type with an indexer andLength
orCount
property - Using ranges with
Span<T>
creates slices without allocating new arrays, providing zero-allocation performance Index
andRange
are structs in theSystem
namespace and can be stored in variables