Индексаторы
46C# --- Руководство по C# --- Индексаторы
Программисты хорошо знакомы с процессом доступа к индивидуальным элементам, содержащимся в стандартных массивах, через операцию индекса ([]). В 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();
}
}
}