Шаг 134.
Язык программирования C#. Начала
Свойства и индексаторы. Многомерные индексаторы

    На этом шаге мы рассмотрим пример использования таких индексаторов.

    Многомерные индексаторы описываются в полной аналогии с двумерными массивами, но только индексов больше, чем два. Для каждого индекса указывается тип и формальное название. Небольшой пример использования многомерного (с четырьмя индексами) индексатора представлен в примере ниже.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr134_1
{
    // Класс с многомерным индексатором: 
    class MyClass {
        // Закрытое целочисленное поле: 
        private int code;
        // Конструктор с целочисленным аргументом: 
        public MyClass(int n) { 
            // Значение поля: 
            code = n;
        }
        // Переопределение метода ToString(): 
        public override string ToString(){
            // Результат метода:
            return "Поле code объекта: " + code;
        }
        // Многомерный индексатор:
        public char this[string a, int i, string b, int j] {
            // Метод вызывается при считывании значения 
            // выражения с проиндексированным объектом: 
            get {
                // Значение выражения: 
                return (char)(a[i] - b[j] + code);
            }
            // Метод вызывается при присваивании значения 
            // выражению с проиндексированным объектом: 
            set {
                // Значение поля: 
                code = value - (a[i] - b[j]);
            }
        }
    }

    // Класс с главным методом: 
    class Program
    {
        // Главный метод:
        static void Main()
        {
            // Создание объекта:
            MyClass obj = new MyClass('A');
            // Проверка значения поля объекта:
            Console.WriteLine(obj);
            // Текстовые переменные: 
            string a = "Alpha", b = "Bravo";
            // Целочисленные переменные: 
            int i = 2, j = 4;
            // Использование индексатора:
            Console.WriteLine("obj[\"{0}\", {1}, \"{2}\", {3}] = {4}", a, i, b, j, 
                    obj[a, i, b, j]); 
            // Использование индексатора: 
            obj[a, i, b, j] = 'F';
            // Проверка значения поля объекта:
            Console.WriteLine(obj);
            // Использование индексатора:
            Console.WriteLine("obj[\"{0}\", {1}, \"{2}\", {3}] = {4}", a, i, b, j, 
                    obj[a, i, b, j]);
            // Новые значения переменных:
            a = "Charlie";
            i = 1;
            j = 2;
            // Использование индексатора:
            Console.WriteLine ("obj[\"{0}\", {1}, \"{2}\", {3}] = {4}", a, i, b, j, 
                   obj[a, i, b, j]);
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    Ниже показан результат выполнения программы.


Рис.1. Результат выполнения программы

    В этом примере класс MyClass содержит:

    Нас, попятно, интересует индексатор. В его get-аксессоре выполняется команда

                return (char)(a[i] - b[j] + code);

    Здесь а и b - текстовые индексы (первый и третий), a i и j - целочисленные индексы (второй и четвертый). То есть принцип вычисления значения выражения такой: из текстовых индексов берем по одному символу и вычисляем разность их кодов. К полученному значению прибавляется значение целочисленного поля code, полученное значение приводится к символьному типу и возвращается как результат. Символы, которые берутся из текстовых индексов, определяются целочисленными индексами в выражении с проиндексированным объектом.

    В set-аксессоре командой

                code = value - (a[i] - b[j]);
полю code присваивается новое значение. Оно вычисляется по такому принципу: от фактически присваиваемого значения (параметр value) отнимается разность кодов символов, определяемых индексами в выражении с проиндексированным объектом.


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

    В главном методе мы создаем объект obj класса MyClass, причем аргументом передается не целое число, а символьное значение 'А'. Это допустимо, поскольку есть автоматическое преобразование значений символьного типа в целочисленное значение. В результате поле code значением получает код символа 'А' (проверка показывает, что это число 65).

    Для индексирования объекта obj мы используем текстовые переменные а и b с начальными значениями "Alpha" и "Bravo", а также целочисленные переменные i и j с начальными значениями 2 и 4. Значение выражения obj[a, i, b, j] в этом случае вычисляется так: в тексте "Alpha" берем символ с индексом 2 (это буква 'р'), а из текста "Bravo" берем символ с индексом 4 (это буква 'о'). Разница между кодами символов 'р' и 'о' равна 1 (между буквами в алфавите одна позиция), и это значение прибавляется к значению 65 поля code, что в итоге дает число 66, и эго код символа 'В'.

    При выполнении команды

            obj[a, i, b, j] = 'F';
новое значение поля code объекта obj вычисляется следующим образом: из кода символа 'F' (число 70) вычитается разность кодов символов 'р' и 'о' (разность кодов равна 1), что дает значение 69. Это новое значение поля code. Понятно, что, если мы теперь проверим значение выражения obj[a, i, b, j], оно окажется равным 'F'.

    Наконец, переменная а получает новое значение "Charlie" (переменная b остается со старым значением "Bravo"), значение переменной i становится равным 1, а значение переменной j теперь равно 2. Если вычислить значение выражения obj[a, i, b, j], то получим такое:

Непосредственная проверка подтверждает наши выводы.

    На следующем шаге мы рассмотрим перегрузку индексаторов.




Предыдущий шаг Содержание Следующий шаг