How to use indices and ranges in C# 8.0

Take advantage of indices and ranges in C# 8.0 to access elements or slices of a collection with simplicity and ease

There are several interesting new features and enhancements in C# 8.0. Indices and ranges are two new additions — available as part of the new System.Index and System.Range types, respectively — that are used for indexing and slicing. This article presents a discussion of how we can work with indices and ranges in C# 8.0.

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here.

Create a console application project in Visual Studio 2019

First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create.

This will create a new .NET Core console application project in Visual Studio 2019. We’ll use this project in the subsequent sections of this article.

Update the language version in Visual Studio

To be able to work with C# 8.0 in Visual Studio, you should use a project that targets .NET Core, just as we’re doing. You will also need to change the language version of the language in use in your project. To do this, follow the steps outlined below:

  1. Right-click on the project.
  2. Select “Properties” to invoke the properties window.
  3. Click Build -> Advanced.
  4. Click on the drop-down control for language version. 
  5. Select C# 8.0 as the language version.
  6. Click OK.

The System.Index and System.Range structs

C# 8.0 introduces two new types, namely System.Index and System.Range. You can use these structs to index or slice collections at runtime. Here is how the System.Index struct is defined in the System namespace.

namespace System
{
    public readonly struct Index
    {
        public Index(int value, bool fromEnd);
    }
}

And here is how the System.Range struct is defined in the System namespace.

namespace System
{
    public readonly struct Range
    {
        public Range(System.Index start, System.Index end);
        public static Range StartAt(System.Index start);
        public static Range EndAt(System.Index end);
        public static Range All { get; }
    }
}

Use System.Index in C# 8.0 to index a collection from the end

There wasn’t any way in C# to index a collection from the end until C# 8.0. You can now take advantage of indexing from the end of a collection by using the unary ^ “hat” operator with an operand that must be System.Int32.

Here is how this predefined index from the end operator is defined in C# 8.0.

System.Index operator ^(int fromEnd);

Let’s understand this with an example. Consider the following array of strings.

string[] cities = { "Kolkata", "Hyderabad", "Bangalore", "London", "Moscow", "London", "New York" };

The following code snippet shows how you can take advantage of the ^ operator to retrieve the city name stored in the last index in the array.

var city = cities[^1];
Console.WriteLine("The selected city is: " + city);

Here is the complete program for your reference.

using System;
namespace RangesAndIndexes
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] cities = { "Kolkata", "Hyderabad", "Bangalore",
            "London", "Moscow", "London", "New York" };
            var city = cities[^1];
            Console.WriteLine("The selected city is: " + city);
            Console.ReadKey();
        }
    }
}

When you execute the program, the output should appear in the console window as shown in the figure below.

csharp 8 systemrange output 01 IDG

Use System.Range in C# 8.0 to extract the subset of a sequence

You can take advantage of System.Range to extract the subset of a sequence when working with arrays and span types. The following code snippet illustrates how you can use a range and index to display the last six characters of a string.

string str = "Hello World!";
Console.WriteLine(str[^6..]);

When you execute the program, the output “World!” should appear in the console window as shown in the figure below.

csharp 8 systemrange output 02 IDG

Here is another example that illustrates how slicing works.

int[] integers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var slice = integers[1..5];
foreach (int i in slice)
Console.WriteLine(i);

When you execute the above program, the numbers 1 through 4 will be displayed at the console window.

You can also pass the range operand inside [ .. ] brackets as shown in the code snippet given below.

string[] cities = { "Kolkata", "Hyderabad", "Bangalore", "London", "Moscow", "London", "New York" };
var data = cities[0..4];
foreach (var city in data)
{
   Console.WriteLine(city);
}

When you execute the program, the first four city names stored in the array will be displayed in the console window.

Before C# 8.0 there wasn’t any syntactically efficient way to access ranges or slices of collections in C#. You now have two new syntactic sugars — the ^ (hat) and ‘..’ (range) operands — for accessing individual elements or ranges in a collection that help make your code clean, readable, and maintainable.

Copyright © 2020 IDG Communications, Inc.