C# 8.0 brings us another nice feature called slicing. In order to make it possible, two new concepts are introduced: Indexes and Ranges.
Let’s see how this tiny feature is supposed to make our life easier 🙂
Goal of slicing
The main purpose of introducing slicing into the language is to make working with arrays and strings easier.
Currently, when you want to retrieve a fragment of an array (X elements from the array, located for instance in its middle), you can use LINQ, i.e. combination of Take and Skip methods. You can also create some extension method to provide kind of slicing.
To illustrate the current way, using LINQ to retrieve only 2nd, 3rd and 4th elements of an array looks as follows:
C# community and designers decided it’s not convenient enough, so are now adding to C# 8 indexes and ranges (in order to provide slicing) 🙂
Index
C# 8.0 comes along with a new object – System.Index. It’s a structure internally and looks as follows:
What’s interesting here, is that the constructor takes the value of the index and boolean flag fromEnd. Let’s see how we can use it in practice:
While the first printed value is nothing special, as you can see we can now use the hat operator (^) in order to index from the end. The following also works:
It means that the ^ operator is a syntactic sugar for Index. I allowed myself to check the IL produced:
As we suspected – an instance of Index is created, passing 3 as value and true as fromEnd (see the constructor parameters above).
Range
Another concept which uses Indexes is a new structural data type – System.Range:
As you can see, it really uses Indexes. We can even try creating it on our own:
This doesn’t really make extracting data from the arrays better than Skip-Take LINQ, does it?
Fortunately, there’s another friendly C# language element introduced called range expression. It can be written as x..y and used directly for indexing:
var array = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' }; | |
Console.WriteLine(array[2..^1]); // prints "CDEFG" |
This looks much better! Let’s see how C# compiler translated our 2 lines of code by looking at the pseudo-C# IL produced:
Even though we could achieve the same with much less LINQ, C# compiler does a lot of stuff for us, keeping our code simpler to grasp.
Ranges in strings
All these operations apply also to strings:
var story = "C# 8 is going to be great!"; | |
Console.WriteLine(story[^6..^0]); // prints "great!" (last 6 chars) |
Ranges in foreach loop
Next interesting usage is in the foreach loop:
var devs = new Developer[] | |
{ | |
new Developer("Dawid"), | |
new Developer("Mark"), | |
new Developer("John"), | |
new Developer("Alice"), | |
new Developer("Kate") | |
}; | |
foreach (var dev in devs[1..^2]) // prints "MarkJohn" | |
{ | |
Console.Write(dev.FirstName); | |
} |
Summary
I see these “little” C# 8 indexes and ranges as another helpful feature. It’s less breaking and controversial than nullable reference types, still making us write less C# code in the future.
If you’d like to dig the feature even more, I encourage you to read the discussions about it on GitHub, which I always find very interesting 😉
Developers, what do you think about C# 8 indexes and ranges? 🤔
[…] more examples on https://www.codejourney.net/csharp-8-slicing-indexes-ranges/. […]