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 anIndexfrom the end:^1is the last element,^2is 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 andLengthorCountproperty - Using ranges with
Span<T>creates slices without allocating new arrays, providing zero-allocation performance IndexandRangeare structs in theSystemnamespace and can be stored in variables