Шаг 130.
Язык программирования C#. Начала
Свойства и индексаторы. Использование индексаторов (еще продолжение)

    На этом шаге мы рассмотрим еще один пример индексатора с одним аксессором.

    Еще один пример индексатора с одним аксессором представлен в следующей программе. Там у индексатора есть только set-аксессор. Рассмотрим приведенный ниже программный код.

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

namespace pr130_1
{
    // Класс с индексатором: 
    class MyString {
        // Закрытое текстовое поле: 
        private string text;
        // Конструктор с текстовым аргументом: 
        public MyString(string t){ 
            text = t;
        }
        // Операторный метод для неявного преобразования 
        // текстового значения в объект класса MyString: 
        public static implicit operator MyString(string t) {
            return new MyString(t);
        }
        // Переопределение метода ToString(): 
        public override string ToString() { 
            return text;
        }
        // Символьный индексатор с целочисленным индексом: 
        public char this[int k] {
            // Метод вызывается при присваивании значения 
            // выражению с индексированным объектом: 
            set {
                // Проверка значения индекса: 
                if (k < 0 || k >= text.Length) return;
                // Текстовая переменная: 
                string t = "";
                // Добавление символов к тексту: 
                for(int i = 0; i < k; i++) { 
                    t += text[i];
                }
                // Добавление в текст присваиваемого символа: 
                t += value;
                // Добавление символов к тексту: 
                for(int i = k + 1; i < text.Length; i++) { 
                    t += text[i];
                }
                // Новое значение текстового поля: 
                text = t;
            }
        }
    }
    
    // Класс с главным методом: 
    class Program
    {
        // Главный метод:
        static void Main()
        {
            // Создание объекта:
            MyString txt = "Myxa";
            // Проверка текста:
            Console.WriteLine(txt);
            // Попытка изменить символ в тексте: 
            txt[-1] = 'Ы';
            // Проверка текста:
            Console.WriteLine(txt);
            // Попытка изменить символ в тексте: 
            txt[4] = 'Ъ';
            // Проверка текста:
            Console.WriteLine(txt);
            // Изменение символа в тексте: 
            txt[0] = 'С';
            // Проверка текста:
            Console.WriteLine(txt);
            // Изменение символа в тексте: 
            txt[1] = 'л';
            // Проверка текста:
            Console.WriteLine(txt);
            // Изменение символа в тексте: 
            txt[2] = 'o';
            // Проверка текста:
            Console.WriteLine(txt);
            // Изменение символа в тексте: 
            txt[3] = 'н';
            // Проверка текста:
            Console.WriteLine(txt);
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

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


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

    В этой программе мы создаем очень скромное подобие класса, предназначенного для работы с текстом. Описанный нами класс с индексатором называется MyString. У класса есть закрытое текстовое поле text и конструктор с текстовым аргументом (переданный конструктору аргумент присваивается значением текстовому полю объекта). Также мы описали операторный метод для неявного приведения типа string в тип MyString. Благодаря этому объектным переменным класса MyString можно присваивать текстовые значения. В результате будет создаваться новый объект класса MyString, а текстовое поле этого объекта определяется тем текстовым значением, которое присваивается объектной переменной.

    Еще в классе MyString переопределен метод ToString(). Переопределен он таким образом, что результатом возвращается текст из поля text.

    Индексатор, описанный в классе MyString, имеет целочисленный индекс, а в нем есть только set-аксессор. Поэтому проиндексированному объекту можно только присвоить значение. Поскольку индексатор описан как относящийся к типу char, то и присваиваться должно символьное значение.

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

 if (k < 0 || k >= text.Length) return;
истинно в том случае, если индекс меньше нуля или больше максимально допустимого индекса в тексте (определяется длиной текста). В этом случае выполняется инструкция return, которая завершает работу аксессора, и с текстовым полем объекта, соответственно, ничего не происходит. Если же этого не происходит, то индекс попадает в допустимый диапазон значений и начинается процесс вычисления нового текстового значения для поля text. Для этого объявляется локальная текстовая переменная t с пустой текстовой строкой в качестве начального значения. Затем запускается цикл, в котором к текстовой строке последовательно дописываются начальные символы из поля text, но только до символа с индексом k (этот символ не копируется). Далее командой
  t += value;
к текстовой строке дописывается тот символ, который присваивается значением выражению с проиндексированным объектом. То есть получается, что вместо символа с индексом k из текстового поля text в текстовую строку дописывается тот символ, что указан в операции присваивания (определяется значением параметра value). Затем снова запускается цикл, с помощью которого к текстовой строке из переменной t дописываются все оставшиеся символы из текстового поля text. По завершении этой конструкции цикла командой
  text = t;
текстовое поле получает новое значение. Новое значение поля text отличается от предыдущего значения одним символом.

    В главном методе программы командой

  MyString txt = "Myxa";
создается объект txt класса MyString (здесь использована операция неявного приведения типов). Также главный метод содержит примеры использования индексатора с индексом, значение которого выходит за допустимый диапазон (команды
  txt[-1] = 'Ы';
и
  txt[4] = 'Ъ';
). Есть также команды (
  txt[0] = 'С';
  txt[1] = 'л';
  txt[2] = 'o';
и
  txt[3] = 'н';
), в которых значение индекса корректно. Для проверки значения текстового поля объекта txt используется переопределение метода ToString() (метод вызывается, когда объект txt передается аргументом методу WriteLine()).

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




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