Г. Шилдт - Полный справочник по C# (1160789), страница 51
Текст из файла (страница 51)
В этом свойстве определен только get-аксессор, и потомусвойство Length можно только читать, но не изменять. Чтобы убедиться в этом, попробуйте убрать символы комментариев в начале следующей строки программы:I // f s . L e n g t h = 1 0 ; // Ошибка, запись запрещена!При попытке скомпилировать программу с этой строкой кода вы получите сообщение об ошибке, уведомляющее о том, что свойство Length предназначено толькодля чтения.Внесение в класс F a i l S o f t A r r a y свойства Length значительно улучшило его, нона этом рано ставить точку.
Член e r r f l a g — еще один кандидат на "превращение"из обычной переменной экземпляра в свойство со всеми преимуществами, посколькудоступ к нему следует ограничить до определения "только для чтения". Приводимокончательную версию класса F a i l S o f t A r r a y , в которой создано свойство Error,использующее в качестве области хранения индикатора ошибки исходную переменную e r r f l a g .// Превращаем переменную e r r f l a g в свойство.using System;class FailSoftArray {int[] a; // Ссылка на базовый массив,int len; // Длина массива.Глава 10. Индексаторы и свойства269bool errflag; // Теперь этот член закрыт.// Создаем массив заданного размера,public FailSoftArray(int size) {a = new int[size];len = size;// Свойство Length предназначено только для чтения,public int Length {get {return len;// Свойство Error предназначено только для чтения,public bool Error {get {return errflag;// Это - индексатор класса FailSoftArray.public int this[int index] {// Это — get-аксессор.get {if(ok(index)) {errflag = falserreturn a[index];} else {errflag = true;return 0;// Это — set-аксессор.set {if(ok(index)) {a[index] = value;errflag = false;}else errflag = true;// Метод возвращает true, если индекс внутри границ,private bool ok(int index) {if(index >= 0 & index < Length) return true;return false;// Демонстрируем улучшенный отказоустойчивый массив,class FinalFSDemo {public static void Main() {FailSoftArray fs = new FailSoftArray(5);// Используем свойство Error.270Часть I.
Язык С #for(int i=0; i < fs.Length + 1;fs[i] = i*10;if(fs.Error)Console.WriteLine("Ошибка в индексе " + i ) ;Создание свойства E r r o r заставило нас внести в класс FailSoftArray два изменения. Во-первых, переменную e r r f l a g пришлось сделать закрытой, поскольку онатеперь используется в качестве базовой области памяти для свойства E r r o r . В результате к члену e r r f l a g теперь нельзя обращаться напрямую. Во-вторых, добавленосвойство E r r o r , предназначенное только для чтения. Отныне программы для выявления ошибок будут опрашивать не поле e r r f l a g , а свойство E r r o r . Это продемонстрировано в методе Main (), в котором умышленно генерируется ошибка нарушенияграниц массива, а для ее обнаружения используется свойство E r r o r .Правила использования свойствНа использование свойств налагаются довольно серьезные ограничения.
Вопервых, поскольку в свойстве не определяется область памяти, его нельзя передаватьметоду в качестве ref- или out-параметра. Во-вторых, свойство нельзя перегружать.(Но при необходимости вы можете иметь два различных свойства, которые используют одну и ту же базовую переменную, но к такой организации свойств прибегаютнечасто.) Наконец, свойство не должно изменять состояние базовой переменной привызове get-аксессора, хотя несоблюдение этого правила компилятор обнаружить не всостоянии. Другими словами, get-операция должна быть максимально простой.Использование индексаторов и свойствНесмотря на то что в предыдущих примерах продемонстрирован механизм работыиндексаторов и свойств, в них не отражена в полной мере вся мощь этих программных средств. В заключение этой главы мы рассмотрим класс RangeArray, использующий индексаторы и свойства для создания массива такого типа, в котором индексный диапазон массива определяется программистом.Как вы знаете, в С# индексация массивов начинается с нуля.
Однако в некоторыхприложениях было бы удобно начинать индексацию массивов с произвольного числа,например с единицы или даже с отрицательного числа, чтобы индексы изменялись вдиапазоне от - 5 до 5. Приведенный здесь класс RangeArray как раз и позволяет подобные способы индексации массивов.При использовании класса RangeArray можно написать такие строки кода:RangeArray га = new RangeArray(-5, 1 0 ) ; // Массив с// индексами от -5 до 10.for(int i = -5; i <= 10; i++) ra[i] = i ; / / Индекс// изменяется от -5 до 10.Нетрудно догадаться, что первая строка создает объект класса RangeArray (массивга), в котором индексы изменяются от - 5 до 10 включительно. Первый аргумент задает начальный индекс, а второй — конечный.Глава 10. Индексаторы и свойства271Ниже представлены классы RangeArray и RangeArrayDemo, демонстрирующиеиспользование этого массива.
Класс RangeArray поддерживает массив int-элементов, но при необходимости можно заменить этот тип данных другим./* Создание класса для поддержки массива с заданнымдиапазоном индексации. Класс RangeArray позволяетначинать индексацию с числа, отличного от нуля.При создании объекта класса RangeArray необходимозадать индексы начала и конца диапазона.Отрицательные индексы также допустимы. Например,можно создать массивы с диапазоном изменения индексовот -5 до 5, от 1 до 10 или от 50 до 56.*/using System;class RangeArray {// Закрытые данные.int[] а; // Ссылка на базовый массив,int lowerBound; // Наименьший индекс,int upperBound; // Наибольший индекс.// Данные для свойств.int len; // Базовая переменная для свойства Length.bool errflag; // Базовая переменная для свойства Error.// Создаем массив с заданным размером,public RangeArray(int low, int high) {high++;if(high <= low) {Console.WriteLine("Неверные индексы.");high = 1 ; // Создаем минимальный массив для// безопасности,low = 0;}а = new int[high - low];len = high - low;lowerBound = low;upperBound = —high;}// Свойство Length, предназначенное только для чтения,public int Length {get {return len;// Свойство Error, предназначенное только для чтения,public bool Error {get {return errflag;// Это — индексатор для класса RangeArray.public int this[int index] {272Часть I.
Язык С #// Это — get-аксессор.get {if(ok(index)) {errflag = false;return a[index - lowerBound];} else {errflag = true;return 0;// Это — set-аксессор.set {if(ok(index) ) {a[index - lowerBound] = value;errflag = false;else errflag = true;// Метод возвращает true, если индекс находится// внутри границ.private bool ok(int index) {if(index >= lowerBound & index <= upperBound)return true;return false;// Демонстрируем использование массива с произвольно// заданным диапазоном индексов,class RangeArrayDeitio {public static void Main() {RangeArray ra = new RangeArray(-5, 5 ) ;RangeArray ra2 = new RangeArray(1, 10);RangeArray ra3 = new RangeArray(-20, -12);// Используем массив га.Console.WriteLine("Длина массива га:+ ra.Length);for(int i = -5; i <= 5;ra[i] = i;Console.Write("Содержимое массива га:for(int i = -5; i <= 5; i++)Console.Write(ra[i] + " " ) ;Console.WriteLine("\n") ;// Используем массив га2.Console.WriteLine("Длина массива га2:+ ra2.Length)for(int i = 1; i <= 10;ra2[i] = i;Console.Write("Содержимое массива га2: " ) ;for(int i = 1; i <= 10;Глава 10.
Индексаторы и свойства273Console.Write(ra2[i] + " " ) ;Console. WriteLine (lf \n") ;// Используем массив гаЗConsole.WriteLine("Длина массива гаЗ: " + гаЗ.Length);for(int i = -20; i <= -12; i++)ra3[i] = i;Console.Write("Содержимое массива гаЗ: ") ;for(int i = -20; i <= -12; i++)Console.Write(гаЗ[i] + " " ) ;Console.WriteLine("\n") ;При выполнении эта программа генерирует такие результаты:Длина массива га: 11Содержимое массива га; - 5 - 4 - 3 - 2 - 1 0 1 2 3 4 5Длина массива га2: 10Содержимое м а с с и в а г а 2 : 1 2 3 4 5 6 7 8 910Длина м а с с и в а г а З : 9Содержимое м а с с и в а г а З : -20 -19 -18 -17 -16 -15 -14 - 1 3 -12Как подтверждают результаты выполнения этой программы, объекты типаRangeArray могут быть индексированы не обязательно начиная с нуля. Рассмотрим,как же реализован класс RangeArray.Определение этого класса начинается с определения закрытых переменных экземра:// Закрытые данные.int[] a; // Ссылка на базовый массив,int lowerBound; // Наименьший индекс,int upperBound; // Наибольший индекс.// Данные для свойств.int len; // Базовая переменная для свойства Length.bool errflag; // Базовая переменная для свойства Error.Базовый массив имеет имя а.