Пользовательские типы с поддержкой диапазонов
Добавляйте поддержку Index и Range в собственные типы.
«Пользовательские типы с поддержкой диапазонов» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Два способа поддержать индексы и диапазоны
Собственные типы могут поддерживать синтаксис Index и Range. Есть два варианта: предоставить явные индексаторы либо предоставить свойство Length/Count и метод Slice.
Явный индексатор Index
Добавьте индексатор, принимающий System.Index, и оператор ^ будет работать с Вашим типом автоматически.
using System;
class Deck {
private int[] cards = { 1, 2, 3, 4, 5 };
public int this[Index i] => cards[i];
}
var d = new Deck();
Console.WriteLine(d[^1]); // 5Явный индексатор Range
Чтобы поддержать создание срезов с помощью .., добавьте индексатор, принимающий System.Range и возвращающий нужный Вам тип среза.
using System;
class Deck {
private int[] cards = { 1, 2, 3, 4, 5 };
public int[] this[Range r] => cards[r];
}
var d = new Deck();
Console.WriteLine(string.Join(",", d[1..3])); // 2,3Шаблон Length + Slice
Компилятор также может автоматически добавить поддержку диапазонов, если в Вашем типе есть свойство Count или Length и метод Slice(int start, int length).
Реализация шаблона
Здесь пользовательский буфер предоставляет Length и Slice. Компилятор самостоятельно преобразует buf[1..3] в buf.Slice(1, 2).
using System;
class Buffer {
private int[] data = { 10, 20, 30, 40 };
public int Length => data.Length;
public int this[int i] => data[i];
public int[] Slice(int start, int length) {
var result = new int[length];
Array.Copy(data, start, result, 0, length);
return result;
}
}
var buf = new Buffer();
Console.WriteLine(string.Join(",", buf[1..3])); // 20,30Почему важен Length
Именно свойство Length (или Count) позволяет компилятору вычислять индексы с отсчётом от конца, например ^1, для Вашего типа. Без него оператор ^ невозможно преобразовать.
using System;
class Buffer {
private int[] data = { 10, 20, 30, 40 };
public int Length => data.Length;
public int this[Index i] => data[i.GetOffset(Length)];
}
var buf = new Buffer();
Console.WriteLine(buf[^1]); // 40Ручное вычисление Index
В индексаторе Index вызовите i.GetOffset(Length), чтобы преобразовать индекс, который может отсчитываться от конца, в обычное смещение.
using System;
class Ring {
private string[] items = { "a", "b", "c" };
public int Length => items.Length;
public string this[Index i] {
get {
int offset = i.GetOffset(Length);
return items[offset];
}
}
}
var r = new Ring();
Console.WriteLine(r[^2]); // bРучное вычисление Range
В индексаторе Range метод r.GetOffsetAndLength(Length) возвращает и начальную позицию, и количество элементов для копирования.
using System;
class Ring {
private int[] items = { 1, 2, 3, 4, 5 };
public int Length => items.Length;
public int[] this[Range r] {
get {
var (start, len) = r.GetOffsetAndLength(Length);
var slice = new int[len];
Array.Copy(items, start, slice, 0, len);
return slice;
}
}
}
var r = new Ring();
Console.WriteLine(string.Join(",", r[^3..^1])); // 3,4Count и Length
Шаблон принимает любое из этих имён: массивы и диапазоны памяти используют Length, а List<T> — Count. Любое из этих свойств удовлетворяет требованиям компилятора.
using System;
using System.Collections.Generic;
var list = new List<int> { 1, 2, 3, 4 };
// List<T> has Count, so Index works:
Console.WriteLine(list[^1]); // 4Проектирование возвращаемых типов Slice
Решите, будет ли Ваш Slice возвращать копию, как для массивов, или представление, как для диапазонов памяти. Представления дешевле, но используют общее изменяемое состояние, поэтому документируйте этот выбор.
Полный пользовательский тип
Этот Sequence поддерживает и ^, и .. благодаря явным индексаторам и свойству Length.
using System;
class Sequence {
private int[] data;
public Sequence(int[] d) => data = d;
public int Length => data.Length;
public int this[Index i] => data[i];
public int[] this[Range r] => data[r];
}
var s = new Sequence(new[] { 5, 10, 15, 20 });
Console.WriteLine(s[^1]); // 20
Console.WriteLine(string.Join(",", s[1..^1])); // 10,15Быстрая проверка
Подтвердите, что понимаете, что позволяет использовать синтаксис диапазонов в пользовательском типе.
Итоги
Вы узнали о двух способах добавить поддержку Index/Range в собственные типы.
- Явные индексаторы, принимающие
IndexиRange. - Неявный шаблон: свойство
Count/Lengthи методSlice(int, int). GetOffset(Length)иGetOffsetAndLength(Length)вычисляют позиции с отсчётом от конца.
Часто задаваемые вопросы
Урок «Пользовательские типы с поддержкой диапазонов» бесплатный?
Да — полный текст урока «Пользовательские типы с поддержкой диапазонов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Пользовательские типы с поддержкой диапазонов»?
Добавляйте поддержку Index и Range в собственные типы. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Пользовательские типы с поддержкой диапазонов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Тип Index и оператор ^
- Тип Range и оператор ..
- Диапазоны с массивами и строками
- Пользовательские типы с поддержкой диапазонов