​Пусть в нашей программе есть массив целых чисел numbers: Перед нами стоит задача: получить новый массив, вырезав из массива numbers элементы от индекса 2 до индекса 4 включительно, то есть должен получится массив . Самое первое и простое решение, которое приходит в голову — это решение в лоб:  Создадим результирующий массив целых чисел result размером 3:   Пройдемся циклом по нужным индексам массива numbers, а именно с 2 до 4 включительно:       Запишем в результирующий массив result нужные значения:      Выведем массив result и убедимся, что все ОК:    С задачей мы справились. Но есть некоторые недостатки:  Для решения такой маленькой задачи, пришлось пройтись циклом. 	  По коду не сразу понятно, что он делает. Таким образом страдает читаемость. 	  Также можно ошибиться с индексами (относится к начинающим программистам).   Следовательно, такое решение нас не устраивает.   Немногие знают, что у списка (List) есть готовый метод GetRange(int index, int count), который получает из списка нужный диапазон элементов. Метод первым параметром принимает index — индекс начала диапазона, а вторым параметром count — количество элементов, которые нужно получить. Например:  GetRange(0, 5) — получает 5 элементов, начиная с индекса 0. 	  GetRange(3, 10) — получает 10 элементов, начиная с индекса 3. Тогда сделаем следующее:   Для того чтобы мы воспользовались готовым методом GetRange, преобразуем массив в список с помощью метода ToList:     Воспользуемся методом GetRange. Нам нужно взять 3 элемента, начиная с индекса 2:      Метод GetRange вернул результат в виде списка (List<int>). Для того чтобы преобразовать его в массив, воспользуемся методом ToArray:      Выведем массив result и убедимся, что все ОК:    С задачей мы справились. Но есть некоторые недостатки:   Для решения такой маленькой задачи, пришлось воспользоваться тремя дополнительными методами. 	  По коду не сразу понятно, что он делает. Таким образом страдает читаемость. 	  Также можно ошибиться при передаче параметров в метод GetRange (относится к начинающим программистам).  	  Данные преобразования ресурсоемкие по памяти и производительности. Вызовы ToList, ToArray проходятся по коллекции и выделяют новую память.   Следовательно, такое решение нас не устраивает.  Можно еще воспользоваться технологией LINQ, а именно двумя методами:  Skip(int count) — возвращает все элементы коллекции, кроме первых count.  	  Take(int count) — возвращает первые count элементов коллекции.  В нашем случае, для того, чтобы взять элементы массива от индекса 2 до индекса 4 включительно, нужно пропустить 2 элемента последовательности, а затем взять первые 3 элемента. Как раз получатся элементы с индексами от 2 до 4.  Посмотрим в коде: С задачей мы справились. Но есть некоторые недостатки:   Для решения такой маленькой задачи, пришлось воспользоваться тремя дополнительными методами. 	  Можно ошибиться при передаче параметров в методы Skip и  Take (относится к начинающим программистам). 	  Данные преобразования ресурсоемкие по памяти и производительности.  Следовательно, такое решение нас не устраивает.  Есть еще статический метод Copy у класса Array: Данный метод копирует элементы из одного массива в другой. Давайте поясним каждый параметр:  Array sourceArray — массив, с которого копируем элементы. 	  int sourceIndex — с какого индекса из массива sourceArray начинаем копировать элементы. 	  Array destinationArray — массив, в который копируются элементы. 	  int destinationIndex — начиная с какого индекса в результирующем массиве destinationArray вставляются элементы. 	  int length — количество элементов, которое нужно скопировать. Давайте воспользуемся данным методом:  Создадим результирующий массив целых чисел result размером 3:   Вызываем метод Copy. Передаем массив numbers и индекс 2 — откуда начинаем вырезать элементы. Затем передаем результирующий массив result и индекс 0 — с какого индекса вставляются элементы. А затем передаем 3 — количество элементов, которое нужно скопировать:      Выведем массив result и убедимся, что все ОК:    С задачей мы справились. Но есть некоторые недостатки:   Легко можно ошибиться при передаче параметров в метод Copy (относится к начинающим программистам).  	  Не сразу понятно как использовать метод Copy, ведь он ничего не возвращает. Нужно понять, что результат возвращается в массиве, который был передан третьим параметром.  Следовательно, такое решение нас не устраивает.    В C# 8 версии добавили дополнительную функциональность для работы с диапазонами (Range). Теперь для решения нашей задачи можно написать вот так:  То есть, для того чтобы получить некоторый диапазон из коллекции, нужно в квадратных скобках указать начальный индекс, затем .. и наконец индекс конца (!!! НЕ включительно !!!).  Например: numbers[3..10] — вырезает элементы, начиная с индекса 3 и заканчивая индексом 9. Напоминаю, что правая граница не включается. 	  numbers[1..7] — вырезает элементы, начиная с индекса 1 и заканчивая индексом 6.  Если индексы будут равны между собой, то в результате получится массив нулевой длины:   Если первый индекс будет больше второго индекса, то возникнет исключение ArgumentOutOfRangeException во время выполнения программы: Можно использовать также индексацию справа налево (Indices), введенную тоже в C# 8 версии, про которую говорили совсем недавно: Можно делать еще более веселые штучки: Например, для получения первых n элементов с помощью диапазонов, нужно написать numbers[0..n]. Так вот, специально для случаев, когда вы хотите взять диапазон с начала массива (когда первый индекс равен 0), придумали упрощение: можно индекс равный 0 опускать, то есть написать вот так: numbers[..n]. Такая запись более предпочтительна.  	 Например, для получения всех элементов, кроме первых n с помощью диапазонов, нужно написать numbers[n..numbers.Length].  Специально для случаев, когда вы хотите взять все элементы, кроме первых n (начиная с индекса n и до конца массива), придумали упрощение. Так как второй индекс всегда равен длине массива, то его можно опустить, то есть написать вот так: numbers[n..]. Такая запись более предпочтительна. 	 Ну и комбинация этих двух подходов. Для получения полной копии массива, можно написать вот так: numbers[..], то есть опустить оба индекса. Это означает взять диапазон от начала массива до конца.  На самом деле любой диапазон в C# 8 версии можно хранить в новом типе данных Range. Он находится в пространстве имен (namespace) System, следовательно, никакой дополнительный using при его использовании не нужно писать.  У Range существует два конструктора: Range() – создает пустой диапазон.  Range(Index start, Index end) – создает диапазон от индекса start (включительно) и до индекса end (НЕ включительно). Рассмотрим на примерах: Заметьте, что объект типа Range передается в качестве индекса в квадратные скобки ().  Проведем соответствие между двумя разными записями: Укороченная версия Версия с Range numbers[2..5] numbers[new Range(2, 5)] numbers[^6..^2] numbers[new Range(^6, ^2)] В Range реализовано неявное преобразование укороченной записи (например 2..5) к Range. Вот как это работает:  У Range переопределен метод Equals: А можно вообще вот так:  Здесь сначала происходит неявное преобразование укороченной записи к Range, а потом вызов Equals.  У Range переопределен также метод ToString: Заметьте, что для индексации с конца выводится ^ перед индексом.  Также теперь мы можем в методы передавать диапазон: Структура Range позволяет создать экземпляр, к которому можно обращаться многократно. Код становится более короткий и  читаемый. Увеличивается производительность без обращения к лишним методам. Меньше нагрузка на память. PS. Написано с любовью вместе со своими учениками. Они у меня лучшие 😍 Net Developer