C# 8: Indexes and Ranges

A new feature with .NET Core 2.1 is the Span type. This type allows direct access to memory in the stack, in the managed heap, and in the native heap. A great feature of the Span type is to take a split of the memory to access only an area within. The next step is to extend this into the C# programming language with ranges. Using ranges you can directly access a range within an array, a string, or a Span.

Sushi selection

This is the third article with features on C# 8. Here are the other ones about nullable reference types, and extensions to pattern matching:

C# 8: Pattern Matching Extended

C# 8 & No More NullReferenceExceptions – What about legacy code?

Framework Requirements

Some C# features require specific types from the framework. For example, interpolated strings are based on the FormattableString class. The foreach statement makes use of IEnumerable, and IEnumerator interfaces. The using statement makes use of the IDisposable interface. These are just a few examples, and there are a lot more. The new C# 8 feature with indexes and ranges makes use of the Index struct, the Range struct, and extension methods for arrays, the Span type, and strings. All these types need to be defined in the System namespace.

The complete source code for the requirements for indexes and ranges be copied from the csharplang GitHub repository.

The Index struct is used to hold an index which not only allows accessing a range from the begin but also from the end. If the index is used from the end, the index is created passing fromEnd = true with the constructor. This way, the inner value is assigned is assigned a value using the bitwise complement operator. This struct defines the Value property that returns the index value, the FromEnd property that returns true if the index is used from the end, and an operator to convert an int value to the Index struct.

The Range struct makes use of the Index. This struct is constructed by invoking static Create, FromStart, ToEnd, and All methods.

  • The Create method accepts two Index parameters to define the range. Remember, the Index type implements an operator to convert int to Index, so you can pass an int as well. The Create method makes use of the private constructor to fill the Start and End properties.
  • The FromStart method just needs one parameter to create a range from the specified start up to the end. `
  • The ToEnd method returns a range from the start to the end point that is referenced with the parameter of the ToEnd method.
  • Finally, the All method returns a range from the begin to the end.

Extension methods are implemented for an int array, a generic array, the string type, Span, a generic Span. The methods implemented are get_IndexerExtension, Slice, and Substring. Some of these methods make use of the Slice method offered by the Span type to create a range.

The Span type is covered in Chapter 17, Managed and Unmanaged Memory of my new book Professional C# 7 and .NET Core 2.0.

Now, let’s look at how these types are used from the new C# 8 syntax – after installing a preview for C# 8.

Install C# 8

At the time of this writing, C# 8 is not yet released. However, you can try it out. At the time of this writing, to try C# 8 ranges, Visual Studio 2017 15.5-15.7 is needed – and the preview of C# Patterns and Ranges. You can easily install it, and uninstall it as described in the referenced article.

Be aware that the features shown here might look different in the released product, or also might be removed or delayed to a later version of C#.

The Hat Operator

We have a new operator – the hat operator. What type do you expect the variable last to be? It’s Index, and references the last element of a range. Using ^, fromEnd is supplied with a true value in the constructor of the Index struct:

This variable can now be used to access the last element of an array. The result shows 3. This is so much simpler compared to using arr.Length - 1 to access the last item:

Using the hat operator indexed by 1 returns the last element of the collection, 2 returns the one before that, 3 the one before that, and so on.

Range

Let’s get into the new range syntax using a string. First, let’s use the traditional ‘Substring’ method of a string. First, the last two words of the string are accessed using the 37nd character (which is the ‘l’), and a string length of 9 characters – this returns the string lazy dogs. Counting the first character of the string from the end, the Length property of the string can be used:

It’s a lot easier to use the range syntax. The range starts from the 9th-last character, and ends after the last. With the range you need to supply the position after the last item with the range end:

Behind the scenes, this gets translated to create two variables of type Index, and to invoke the Range.Create method with returns a Range value. Next, the new extension method of the string, Substring is used to pass a Range:

Instead of supplying the element after the last item, you can simple use [^9..] to access the latest nine elements. This is translated to an invocation of Range.FromStart. Similar, counting from the beginning, you can use [36..] to count from the 37nd character up to the end. Starting from the beginning up to the nth element, you can use [..9]. This translates to the method Range.ToEnd. Just supplying two dots [..] returns the complete collection with Range.All.

Ranges with Arrays

Let’s use the range syntax with a simple array. Here, using the range [2..5] returns a Span containing the 3rd up to the 5th element. Applying the range on an array invokes the Slice method of the Range struct which in turn invokes the AsSpan method on the array, and the Slice method of the Span passing the start and length. Because the Span type directly references the memory from the array, you can use ref locals to create a variable directly referencing the element from the array. This allows changing of the array element. Not using the syntax for ref return copies the value into a local int.

ref locals are part of C# 7 and discussed in a previous blog post C# 7.0 Out Vars and Ref Returns.

Summary

C# 7 introduced ref locals and ref returns, as well as more enhancements on reference semantics. The Span type allows directly referencing memory on the heap and on the stack. The Span type makes it easy to create slices with the Slices method. With C# 8, the tour continuous, and we get C# syntax on using ranges, which can be used to create substrings as well.

What do you think about this new C# 8 feature?

Get the complete sample from More Samples!

If you found this information valuable and want to return me a favor, then buy me a coffee.

Buy Me A Coffee

Before C# 8 is released, read about all the cool C# 7 features in the book Professional C# 7 and .NET Core 2.0!

Enjoy programming and learning,
Christian

Advertisements

5 thoughts on “C# 8: Indexes and Ranges

    1. Thanks for the comment.
      You’re right – just the method name is good enough 🙂 I didn’t mention this in this article.
      With C# 7, the await keyword works with a GetAwaiter method as well and doesn’t require the Task type.

      Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.