Оператор шляпы (^) и оператор диапазона (..) обеспечивают другой синтаксис для доступа к элементам в массиве: Span или ReadOnlySpan. Оператор диапазона используется для указания начала и конца диапазона для последовательности.

Давайте посмотрим на несколько примеров. Рассмотрим следующий код, в котором у вас есть массив строк и вы хотите получить первые четыре элемента:

static void Main(string[] args)
{
  var people = new string[] { "Jane", "Jean", "Grey", "Marcus", "Theophilus", "Keje" };
  var firstFour = GetFirstFourPersons(people);

  foreach (var person in firstFour)
  {
    Console.WriteLine(person);
  }
}

static string[] GetFirstFourPersons(string[] people)
{
  var result = new string[4];
  for (int i = 0; i < 4; i++)
  {
    result[i] = people[i];
  }
  return result;
}

// result:
// Jane
// Jean
// Grey
// Marcus

Мы можем переписать его с помощью оператора диапазона, передав операнд диапазона внутри [ и ].

static void Main(string[] args)
{
  var people = new string[] { "Jane", "Jean", "Grey", "Marcus", "Theophilus", "Keje" };
  var firstFour = people[0..4];

  foreach (var person in firstFour)
  {
    Console.WriteLine(person);
  }
}

Это дает тот же результат, что и в предыдущем примере. До и после оператора .. находятся начальный и конечный индексы, из которых следует получить последовательность данных. Он не включает элемент в конечный индекс как часть результата.

Ассортимент также может быть неограниченным. Это означает, что вы можете опустить начальный индекс, конечный индекс или и то, и другое.

var all = people[..]; // contains all the elements from the origin array
var firstFour = people[..4]; // contains "Jane", "Jean", "Grey", and "Marcus"
var lastTwo = people[4..]; // contains "Theophilus" and "Keje"

Переменная all открыта на обоих концах и поэтому возвращает все элементы. Его также можно записать как var all = people[0..people.Length]. Если вы опустите начальный индекс, он будет использовать 0 в качестве начального индекса, а если это конечный индекс, он будет использовать значение sequence.Length для разрешения значения.

Вы также можете объявить переменные диапазона:

Range firstFourRange = ..4
var firstFour = people[firstFourRange]; // contains "Jane", "Jean", "Grey", and "Marcus"

В C # 8 вы можете указать, что индекс отсчитывается относительно конца массива. Вы делаете это с помощью оператора ^. Учитывая массив people, мы можем получить последний элемент в последовательности, используя people[^1]. ^0 такой же, как people.Length. Поэтому, если вы используете people[^0] для получения последнего элемента последовательности, вы получите исключение, потому что он находится за пределами допустимого диапазона. Мы можем использовать это с оператором диапазона:

Range lastTwoElement = ^2..
var lastTwo = people[lastTwoElement] // contains "Theophilus" and "Keje"

Это даст нам два последних имени. Отсутствие конечного индекса означает использование ^0 (т.е. people.Length) в качестве конечного индекса. Мы также можем присвоить индекс переменной:

Index lastIndex = ^1;
string value = people[lastIndex];

Эта языковая поддержка основана на двух новых типах: System.Index и System.Range. Тип Index представляет индекс в последовательности, а тип Range определяет поддиапазон последовательности.