Язык программирования C#9 и платформа .NET5
public sealed class DataTableCollection : InternalDataCollectionBase{...// Перегруженные индексаторы.public DataTable this[int index] { get; }public DataTable this[string name] { get; }public DataTable this[string name, string tableNamespace] { get; }}Поддержка индексаторных методов вполне обычна для типов в библиотеках базовых классов. Поэтому даже если текущий проект не требует построения специальных индексаторов для классов и структур, помните о том, что многие типы уже поддерживают такой синтаксис.
Многомерные индексаторы
Допускается также создавать индексаторный метод, который принимает несколько параметров. Предположим, что есть специальная коллекция, хранящая элементы в двумерном массиве. В таком случае индексаторный метод можно определить следующим образом:
public class SomeContainer{private int[,] my2DintArray = new int[10, 10];public int this[int row, int column]{ /* получить или установить значение в двумерном массиве */ }}Если только вы не строите высокоспециализированный класс коллекций, то вряд ли будете особо нуждаться в создании многомерного индексатора. Пример ADO.NET еще раз демонстрирует, насколько полезной может оказаться такая конструкция. Класс
в ADO.NET по существу представляет собой коллекцию строк и столбцов, похожую на миллиметровку или на общую структуру электронной таблицы Microsoft Excel.DataTableХотя объекты
обычно наполняются без вашего участия с использованием связанного "адаптера данных", в приведенном ниже коде показано, как вручную создать находящийся в памяти объектDataTable, который содержит три столбца (для имени, фамилии и возраста каждой записи). Обратите внимание на то, как после добавления одной строки вDataTableс помощью многомерного индексатора производится обращение ко всем столбцам первой (и единственной) строки. (Если вы собираетесь следовать примеру, тогда импортируйте в файл кода пространство именDataTable.)System.Datastatic void MultiIndexerWithDataTable(){// Создать простой объект DataTable с тремя столбцами.DataTable myTable = new DataTable();myTable.Columns.Add(new DataColumn("FirstName"));myTable.Columns.Add(new DataColumn("LastName"));myTable.Columns.Add(new DataColumn("Age"));// Добавить строку в таблицу.myTable.Rows.Add("Mel", "Appleby", 60);// Использовать многомерный индексатор для вывода деталей первой строки.Console.WriteLine("First Name: {0}", myTable.Rows[0][0]);Console.WriteLine("Last Name: {0}", myTable.Rows[0][1]);Console.WriteLine("Age : {0}", myTable.Rows[0][2]);}Начиная с главы 21, мы продолжим рассмотрение ADO.NET, так что не переживайте, если что-то в приведенном выше коде выглядит незнакомым. Пример просто иллюстрирует, что индексаторные методы способны поддерживать множество измерений, а при правильном применении могут упростить взаимодействие с объектами, содержащимися в специальных коллекциях.
Определения индексаторов в интерфейсных типах
Индексаторы могут определяться в выбранном типе интерфейса .NET Core, чтобы позволить поддерживающим типам предоставлять специальные реализации. Ниже показан простой пример интерфейса, который задает протокол для получения строковых объектов с использованием числового индексатора:
public interface IStringContainer{string this[int index] { get; set; }}При таком определении интерфейса любой класс или структура, которые его реализуют, должны поддерживать индексатор с чтением/записью, манипулирующий элементами с применением числового значения. Вот частичная реализация класса подобного вида:
class SomeClass : IStringContainer{private List<string> myStrings = new List<string>();public string this[int index]{get => myStrings[index];set => myStrings.Insert(index, value);}}На этом первая крупная тема настоящей главы завершена. А теперь давайте перейдем к исследованиям языкового средства, которое позволяет строить специальные классы и структуры, уникальным образом реагирующие на внутренние операции С#. Итак, займемся концепцией перегрузки операций.
Понятие перегрузки операций
Как и любой язык программирования, C# имеет заготовленный набор лексем, используемых для выполнения базовых операций над встроенными типами. Например, вы знаете, что операция
может применяться к двум целым числам, чтобы получить большее целое число:+// Операция + с целыми числами.int a = 100;int b = 240;int c = <b>a + b</b>; // с теперь имеет значение 340Опять-таки, здесь нет ничего нового, но задумывались ли вы когда-нибудь о том, что одну и ту же операцию
разрешено использовать с большинством встроенных типов данных С#? Скажем, взгляните на следующий код:+