Индексаторы
Программисты хорошо знакомы с процессом доступа к индивидуальным элементам, содержащимся в стандартных массивах, через операцию индекса ([]). В C# имеется возможность проектировать специальные классы и структуры, которые могут быть индексированы подобно стандартному массиву, посредством определения индексатора. Это конкретное языковое средство наиболее полезно при создании специальных типов коллекций (обобщенных и необобщенных). Индексаторы могут быть одно- или многомерными.
Одномерные индексаторы
Ниже приведена общая форма одномерного индексатора:
тип_элемента this[int индекс] { // Аксессор для получения данных, get { // Возврат значения, которое определяет индекс. } // Аксессор для установки данных, set { // Установка значения, которое определяет индекс. }}
где тип_элемента обозначает конкретный тип элемента индексатора. Следовательно, у каждого элемента, доступного с помощью индексатора, должен быть определенный тип_элемента. Этот тип соответствует типу элемента массива. Параметр индекс получает конкретный индекс элемента, к которому осуществляется доступ. Формально этот параметр совсем не обязательно должен иметь тип int, но поскольку индексаторы, как правило, применяются для индексирования массивов, то чаще всего используется целочисленный тип данного параметра.
В теле индексатора определены два аксессора (т.е. средства доступа к данным): get и set. Аксессор подобен методу, за исключением того, что в нем не объявляется тип возвращаемого значения или параметры. Аксессоры вызываются автоматически при использовании индексатора, и оба получают индекс в качестве параметра. Так, если индексатор указывается в левой части оператора присваивания, то вызывается аксессор set и устанавливается элемент, на который указывает параметр индекс. В противном случае вызывается аксессор get и возвращается значение, соответствующее параметру индекс. Кроме того, аксессор set получает неявный параметр value, содержащий значение, присваиваемое по указанному индексу.
Давайте рассмотрим пример:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class MyArr { int[] arr; public int Length; public MyArr(int Size) { arr = new int[Size]; Length = Size; } // Создаем простейший индексатор public int this[int index] { set { arr[index] = value; } get { return arr[index]; } } } class Program { static void Main() { MyArr arr1 = new MyArr(Size: 5); Random ran = new Random(); // Инициализируем каждый индекс экземпляра класса arr1 for (int i = 0; i < arr1.Length; i++) { arr1[i] = ran.Next(1,100); Console.Write("{0}\t", arr1[i]); } Console.ReadLine(); } } }
В текущем классе MyArr определен индексатор, позволяющий вызывающему коду идентифицировать подэлементы с применением числовых значений. Однако надо понимать, что это не обязательное требование метода-индексатора.
Следует особо подчеркнуть, что индексатор совсем не обязательно должен оперировать массивом. Его основное назначение — предоставить пользователю функциональные возможности, аналогичные массиву.
На применение индексаторов накладываются два существенных ограничения. Во-первых, значение, выдаваемое индексатором, нельзя передавать методу в качестве параметра ref или out, поскольку в индексаторе не определено место в памяти для его хранения. И во-вторых, индексатор должен быть членом своего класса и поэтому не может быть объявлен как static.
Многомерные индексаторы
Можно также создавать индексатор, принимающий несколько параметров:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class MyArr { int[,] arr; // Размерность двухмерного массива public int rows, cols; public int Length; public MyArr(int rows, int cols) { this.rows = rows; this.cols = cols; arr = new int[this.rows, this.cols]; Length = rows * cols; } // Индексатор public int this[int index1, int index2] { get { return arr[index1, index2]; } set { arr[index1, index2] = value; } } } class Program { static void Main(string[] args) { Random ran = new Random(); Console.WriteLine("Arr1: \n"); MyArr arr1 = new MyArr(4,5); for (int i = 0; i < arr1.rows - 1; i++) { for (int j = 0; j < arr1.cols - 1; j++) { arr1[i, j] = ran.Next(1,20); Console.Write(arr1[i, j] + "\t"); } Console.WriteLine(); } Console.ReadLine(); } } }
Комментарии