Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 5:

Контролирующий код C#

< Лекция 4 || Лекция 5: 123 || Лекция 6 >

Индексаторы

Создание объектов с контролирующим кодом, имитирующих работу массивов, является главной целью индексаторов. Существующий массив может упаковываться в поле класса, а один из общедоступных методов класса, который и называется индексатором, допускает форму вызова через объект класса по синтаксису массива. Индексаторы, как и массивы, бывают одномерными и многомерными.

Одномерный индексатор задается по следующему синтаксису:

// Одномерный индексатор - специфический метод класса
        тип_элемента this[int индекс]
        {
            // Аксессор чтения
            get
            {
                // Возврат значения, 
                // заданного элементом "индекс"
            }
            // Аксессор записи
            set
            {
                // Установка значения для элемента,
                // адресуемого с помощью "индекс"
            }
        }

Тип_элемента устанавливает тип индексируемых элементов, доступ к которым предоставляет индексатор. При использовании индексатора аксессоры вызываются автоматически и могут использовать значение индекс. Если индексатор стоит слева от оператора присваивания, то срабатывает аксессор set, которому передается в переменной value значение выражения для присваивания, стоящего справа. Если индексатор стоит справа от оператора присваивания, то срабатывает аксессор get, который должен вернуть какое-то значение переменной, стоящей слева. Фактически это то же самое, что и функции доступа, только используется синтаксис массивов.

Многомерный индексатор отличается от одномерного только тем, что вместо единственного индекса имеет список индексов, например, три индекса. Индексаторы должны быть объявлены с модификатором publi c, чтобы быть доступными во внешнем коде.

// Многомерный индексатор
        тип_элемента this[int индекс1, int index2, int index3]
        {
            // Аксессор чтения
            get
            {
                // Что-то делаем, используя индексы,
        // и возвращаем единственное значение
            }
            // Аксессор записи
            set
            {
                // Что-то делаем, используя индексы
            }
        }
// Файл Program.cs
using System;
    
class MyClass
{
    public MyClass()
    {
        // Настройка консоли
        Console.Title = "Использование индексаторов";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
    
        // Создаем объект класса, инкапсулирующего целочисленный массив
        const int SIZE = 4;
        ControlBordersArray arrayControl = new ControlBordersArray(SIZE);
        // Наполняем значениями
        for (int i = 0; i < arrayControl.Length; i++)
            arrayControl[i] = i + 1;
    
        // Печатаем исходный
        Console.WriteLine("Исходный массив:");
        for (int i = 0; i < arrayControl.Length; i++)
            Console.Write("{0, -3}", arrayControl[i]);
        // Перевод на новую строку и пустая строка
        Console.WriteLine(Environment.NewLine); 
    
        // Адресуемся за границы внутреннего массива
        arrayControl[-5] = 20;
        arrayControl[5] = 30;
    
        // Опять печатаем
        Console.WriteLine("Измененный массив:");
        for (int i = 0; i < arrayControl.Length; i++)
            Console.Write("{0, -3}", arrayControl[i]);
    }
}
    
// Упаковка массива в класс
class ControlBordersArray
{
    // Закрытые поля класса
    int[] array; // Ссылка на одномерный массив
    int length;  // Длина массива
    
    // Конструктор с параметрами
    public ControlBordersArray(int size)
    {
        length = size;         // Установили параметр длины
        array = new int[length]; // Создали одномерный массив
    }
    
    // Конструктор по умолчанию
    public ControlBordersArray()
    {
        length = 16;         // Установили параметр длины
        array = new int[length]; // Создали одномерный массив
    }
    
    // Публичное свойство только для чтения
    public int Length
    {
        get { return length; }
    }
    
    // Публичный метод - индексатор
    // При выходе индекса за границы работать с пограничными элементами
    public int this[int index]
    {
        get
        {
            if (index < 0)
                return array[0];
            else if (index >= length)
                return array[length - 1];
            else
                return array[index];
        }
        set
        {
            if (index < 0)
                array[0] = value;
            else if (index >= length)
                array[length - 1] = value;
            else
                array[index] = value;
        }
    }
}
    
class Program
{
    static void Main()
    {
        new MyClass();// Чтобы сработал конструктор
        // Для задержки консольного окна
        Console.ReadLine();
    }
}

Приведенный пример демонстрирует создание контролирующего границы кода при работе с элементами упакованного в класс массива. Но базового массива внутри класса может и не быть, а значения якобы хранящихся элементов массива фактически будут при каждом обращении вычисляться на лету. Конечно, индексатор для этого случая должен использоваться только для чтения без аксессора set.

В качестве примера приведем класс с двумя перегруженными индексаторами, один из которых на лету генерирует элементы таблицы умножения, другой - квадраты чисел. Какой индексатор присоединить в вызывающем коде, решает компилятор по сигнатуре индексатора (в нашем случае - по числу параметров). Также приведем метод, функциональность которого эквивалентна индексатору, только его применение построено в ином - традиционном синтаксисе.

// Файл Program.cs
namespace Test
{
    using System; // Инструкция может быть и внутри пространства имен
    
    class MyClass
    {
        public MyClass()
        {
            // Настройка консоли
            Console.Title = "Использование индексаторов";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
    
            // Создаем объект таблицы умножения
            MultiplicationTable table = new MultiplicationTable();
            string str;
    
            // Используем многомерный индексатор 
            // и распечатываем таблицу умножения
            Console.WriteLine("Таблица умножения по индексатору");
            for (int i = table.MinValue; i <= table.MaxValue; i++)
            {
                str = "";
                for (int j = table.MinValue; j <= table.MaxValue; j++)
                    str += String.Format("{0}x{1}={2, -3}  
                      ", i, j, table[i, j]);
                Console.WriteLine(str);
            }
    
            // Используем перегруженный одномерный индексатор 
            // и распечатываем квадраты чисел
            Console.WriteLine(Environment.NewLine +
                "Квадраты первых чисел натурального ряда");
                str = "";
                for (int i = table.MinValue; i <= table.MaxValue; i++)
                    str += String.Format("{0}x{0}={1, -3}  
                      ", i, table[i]);
                Console.WriteLine(str);
    
            // Используем метод и распечатываем таблицу умножения
            Console.WriteLine("\r\nТаблица умножения по методу");
            for (int i = table.MinValue; i <= table.MaxValue; i++)
            {
                str = "";
                for (int j = table.MinValue; j <= table.MaxValue; j++)
                    str += String.Format("{0}x{1}={2, -3}  ",
                            i, j, table.Get(i, j));
                Console.WriteLine(str);
            }
        }
    }
    
    // Имитация таблицы умножения
    class MultiplicationTable
    {
        // Свойства
        public int MinValue
        {
            get { return 1; }
        }
    
        public int MaxValue
        {
            get { return 9; }
        }
    
        // Публичный индексатор
        // имитирующий элементы таблицы умножения
        public int this[int index1, int index2]
        {
            get
            {
            int indexMin = Math.Min(index1, index2);
            int indexMax = Math.Max(index1, index2);
            if (indexMin >= MinValue && indexMax <= MaxValue)
               return index1 * index2;
            else
            {
            Console.WriteLine("Это уже высшая математика");
            return 0;
            }
            }
        }
    
        // Обычный метод
        // Код точно такой, что и в многомерном индексаторе
        public int Get(int index1, int index2)
        {
            int indexMin = Math.Min(index1, index2);
            int indexMax = Math.Max(index1, index2);
            if (indexMin >= MinValue && indexMax <= MaxValue)
                return index1 * index2;
            else
            {
                Console.WriteLine("Это уже высшая математика");
                return 0;
            }
        }
    
        // Перегруженный индексатор, возвращающий квадраты чисел
        public int this[int index]
        {
            get
            {
            if (index >= MinValue && index <= MaxValue)
                return index * index;
            else
            {
            Console.WriteLine("Это уже высшая математика");
            return -1;
            }
            }
        }
    }
    
    class Program
    {
        static void Main()
        {
            new MyClass();// Чтобы сработал конструктор
            // Для задержки консольного окна
            Console.ReadLine();
        }
    }
}

< Лекция 4 || Лекция 5: 123 || Лекция 6 >
Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?