Индексаторы. Определение одномерного индексатора. Класс «Безопасный массив». Виртуальный массив.
Определение одномерного индексатора
В некоторых ситуациях бывает удобно индексировать (нумеровать) содержимое объекта так, словно он представляет собой массив. Особенно если поля класса представляют собой массив, стек или какие-то перечисления. Такая задача решается разработкой индексатора.
Индексация массивов реализуется с помощью оператора массива, который обозначается [ ]. С его помощью, можно получить доступ к отдельному элементу массива (mas[2], ... , mas[i]).
C# позволяет строить пользовательские классы и структуры, которые могут индексироваться как массивы. Тогда к i-ому элементу значения объекта можно подступиться как Ob[i].
Свойства и индексаторы расширяют возможности класса. Свойства предлагают эффективный способ управления доступом к данным объекта. Индексаторы обеспечивают механизм, посредством которого к объектам можно получать доступ по индексам на основе синтаксиса массивов. То есть индексируемый объект выглядит как массив, но для выполнения индексации в нём определяют специальные функции доступа.
Итак, индексатор позволяет обеспечить индексируемый доступ к объекту. Его главное назначение – создавать специализированные (ранжированные) массивы, на которые налагается одно или несколько ограничений. Индексаторы позволяют использовать синтаксис работы с массивами для доступа к классу, который содержит: массив, какие-то перечисления (enum), а так же наборы (коллекции или семейства). При использовании индексаторов пользовательские коллекции работают с базовыми библиотеками .NET.
Индексатор в C# представляет собой несколько «искажённое» свойство. Индексаторы могут характеризоваться одной или несколькими размерностями.
Создание одномерных индексаторов. Формат записи одномерного индексатора:
public Тип_элемента_объекта this [int индекс] // this - этот
{
Get //Аксессор считывания данных
{
//Возврат значения, заданного индексом.
}
Set //Аксессор установки данных.
{
//Установка значения элементу, заданному индексом
}
}
Объявление индексатора похоже на объявление свойства, но в нём используются указатель this и индекс. Оба аксессора в качестве параметра принимают индекс. Например:
Ob[5] = 13.87; // [5] - это и есть индексатор. Здесь работал set- аксессор.
double z = Ob[2] + 100; // Здесь работал get-аксессор.
Класс «Безопасный массив»
Задание: В проекте «Первые_учебные_классы» создать класс Bezopasn_mas (Безопасный массив) с использование одномерного индексатора. Под безопасностью понимается проверка выхода индекса за пределы границ массива.
class Bezopasn_mas
{
double [] mas; //
Int dlina; // Закрытые поля класса
bool errflag; //
// Конструктор:
public Bezopasn_mas(int size)
{
dlina = size;
mas = new double[size]; // Позднее связывание ссылочной переменной с памятью.
}
// Свойства:
Public int Razmer
{
get { return dlina; }
}
Public bool Oshibka
{
get { return errflag; }
}
}
Для разработки индексатора создадим закрытый вспомогательный метод OK(int index), который возвращает true, если индекс находится в пределах границ массива, а иначе возвращает false.
Private bool OK(int index)
{
if (index >= 0 && index < Razmer)
return true;
Else
return false;
}
// Индексатор:
public double this [int index]
{
Get
{
If (OK(index))
{
errflag = false; // Ошибки нет!
return mas[index];
}
Else
{
errflag = true; //Ошибка индекса!
Return 0; // С целью безопасности программа должна работать далее. Мы возвращаем ноль.
}
}
Set
{
If (OK(index))
{
errflag = false; //Ошибки нет!
mas[index] = value;
}
Else
errflag = true;
}
}
//В Main():
Bezopasn_mas Ob1 = new Bezopasn_mas(5);
int i=0; double x=0;
Console.WriteLine("Мягкое приземление! Работа с массивом без уведомлений об ошибках");
Заполняя массив, нарушим его границы:
for (i = 0; i < Ob1.Razmer * 2; i++)
{
Console.WriteLine("Введите " + i + " элемент массива!");
Ob1[i] = Double.Parse(Console.ReadLine());
}
Console.WriteLine("Содержимое массива");
for (i = 0; i < Ob1.Razmer * 2; i++)
{
x = Ob1[i];
Console.Write(x+ " ");
}
Console.WriteLine();
//Выполнить!
Console.WriteLine("Работа с объектом-массивом с выдачей сообщений об ошибке!");
for (i = 0; i < Ob1.Razmer * 2; i++)
{
Console.WriteLine("Введите " + i + " элемент массива!");
Ob1[i] = Double.Parse(Console.ReadLine());
if (Ob1.Oshibka)
Console.WriteLine("Элемент с номером " + i + " вне границ!");
}
Console.WriteLine("Содержимое массива");
for (i = 0; i < Ob1.Razmer * 2; i++)
{
x = Ob1[i];
if (Ob1.Oshibka)
Console.WriteLine("Элемент с номером " + i + " вне границ!");
Console.Write(x+ " ");
}
Console.WriteLine();
Виртуальный массив
Индексатор может не использовать базовый массив, объявленный в классе. Вполне достаточно, чтобы индексатор обеспечивал функционирование, которое для пользователя выглядело бы так, как будто идёт работа с массивом (виртуальный массив).
Задание: В проект «Первые_учебные_классы» добавить новый класс: Stepeni_2. В этом классе создать индексатор, который действует подобно массиву, предназначенному только для чтения. Такой виртуальный массив будет содержать степени числа 2 от 0 до 15. В действительности же никакого массива НЕТ. Роль индекса будет играть показатель степени.
Существует много алгоритмов, в которых вычисляется какой-то i-й элемент: числа Фибоначчи, целая степень числа, очередной член ряда Тейлора и другие.
//Разработка класса Stepeni_2:
//Вспомогательный закрытый метод Stepen(int pokaz):