1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 50
Текст из файла (страница 50)
Во-вторых, добавлено свойствоError, предназначенное только для чтения. Отныне программы для выявления ошибокбудут опрашивать не поле errflag, а свойство Error. Это продемонстрировано в методеMain(), в котором умышленно генерируется ошибка нарушения границ массива, а для ееобнаружения используется свойство Error.Правила использования свойствНа использование свойств налагаются довольно серьезные ограничения. Во-первых,поскольку в свойстве не определяется область памяти, его нельзя передавать методу вкачестве ref- или out-параметра. Во-вторых, свойство нельзя перегружать. (Но принеобходимости вы можете иметь два различных свойства, которые используют одну и ту жебазовую переменную, но к такой организации свойств прибегают нечасто.) Наконец,свойство не должно изменять состояние базовой переменной при вызове get-аксессора,хотя несоблюдение этого правила компилятор обнаружить не в состоянии.
Другимисловами, get-операция должна быть максимально простой.Использование индексаторов и свойствНесмотря на то что в предыдущих примерах продемонстрирован механизм работыиндексаторов и свойств, в них не отражена в полной мере вся мощь этих программныхсредств. В заключение этой главы мы рассмотрим класс RangeArray, использующийиндексаторы и свойства для создания массива такого типа, в котором индексный диапазонмассива определяется программистом.Как вы знаете, в C# индексация массивов начинается с нуля. Однако в некоторыхприложениях было бы удобно начинать индексацию массивов с произвольного числа,например с единицы или даже с отрицательного числа, чтобы индексы изменялись вдиапазоне от -5 до 5. Приведенный здесь класс RangeArray как раз и позволяет подобныеспособы индексации массивов.При использовании класса RangeArray можно написать такие строки кода:RangeArray rа = new RangeArray(-5, 10); // Массив с// индексами от -5 до 10.for(int i = -5; i <= 10; i++) ra[i] = i; // Индекс// изменяется от -5 до 10.Нетрудно догадаться, что первая строка создает объект класса RangeArray (массивra), в котором индексы изменяются от -5 до 10 включительно.
Первый аргумент задаетначальный индекс, а второй — конечный.Глава 10. Индексаторы и свойства271Ниже представлены классы RangeArray и RangeArrayDemo, демонстрирующиеиспользование этого массива. Класс RangeArray поддерживает массив int-элементов, нопри необходимости можно заменить этот тип данных другим./* Создание класса для поддержки массива с заданнымдиапазоном индексации. Класс RangeArray позволяетначинать индексацию с числа, отличного от нуля.При создании объекта класса RangeArray необходимозадать индексы начала и конца диапазона.Отрицательные индексы также допустимы.
Например,можно создать массивы с диапазоном изменения индексовот -5 до 5, от 1 до 10 или от 50 до 56. */using System;class RangeArray {// Закрытые данные.int[] a; // Ссылка на базовый массив.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;}a = 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.
Язык C#// Это — 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 RangeArrayDemo {public static void Main() {RangeArray ra = new RangeArray(-5, 5);RangeArray ra2 = new RangeArray(1, 10);RangeArray ra3 = new RangeArray(-20, -12);// Используем массив ra.Console.WriteLine("Длина массива ra: " + ra.Length);for(int i = -5; i <= 5; i++)ra[i] = i;Console.Write("Содержимое массива ra: ");for(int i = -5; i <= 5; i++)Console.Write(ra[i] + " ");Console.WriteLine("\n");// Используем массив ra2,Console.WriteLine("Длина массива ra2: " + ra2.Length);for(int i = 1; i <= 10; i++)ra2[i] = i;Console.Write("Содержимое массива ra2: ");for(int i = 1; i <= 10; i++)Глава 10.
Индексаторы и свойства273Console.Write(ra2[i] + " ");Console.WriteLine("\n");// Используем массив ra3Console.WriteLine("Длина массива ra3: " + ra3.Length);for(int i = -20; i <= -12; i++)ra3[i] = i;Console.Write("Содержимое массива ra3: ");for(int i = -20; i <= -12; i++)Console.Write(ra3[i] + " ");}}Console.WriteLine("\n");При выполнении эта программа генерирует такие результаты:Длина массива ra: 11Содержимое массива ra: -5 -4 -3 -2 -1 0 1 2 3 4 5Длина массива ra2: 10Содержимое массива rа2: 1 2 3 4 56 7 8 9 10Длина массива ra3: 9Содержимое массива ra3: -20 -19 -18 -17 -16 -15 -14 -13 -12Как подтверждают результаты выполнения этой программы, объекты типаRangeArray могут быть индексированы не обязательно начиная с нуля.
Рассмотрим, какже реализован класс RangeArray.Определение этого класса начинается с определения закрытых переменныхэкземпляра:// Закрытые данные.int[] а; // Ссылка на базовый массив.int lowerBound; // Наименьший индекс.int upperBound; // Наибольший индекс.// Данные для свойств.int len; // Базовая переменная для свойства Length.bool errflag; // Базовая переменная для свойства Error.Базовый массив имеет имя а. Он размешается в памяти с помощью конструкторакласса RangeArray.
Индекс нижней границы массива сохраняется в закрытой переменнойlowerBound, а индекс верхней границы — в закрытой переменной upperBound. Затемобъявляются переменные элемента, которые поддерживают свойства Length и Error.Конструктор класса RangeArray имеет такой вид:// Создаем массив с заданным размером.public RangeArray(int low, int high) {high++;if(high <= low) {Console.WriteLine("Неверные индексы.");high = 1;// Создаем минимальный массив для// безопасности.low = 0;274Часть I.
Язык C#}}а = new int[high - low];len = high - low;lowerBound = low;upperBound = --high;Объект типа RangeArray создается в результате передачи нижнего граничногоиндекса в параметр low и верхнего граничного индекса — в параметр high. Значениеhigh затем инкрементируется, чтобы вычислить размер массива, поскольку задаваемыеиндексы изменяются от low до high включительно. После этого проверяем, действительноли верхний индекс больше нижнего. Если это не так, выводится сообщение об ошибке виндексах и создается одноэлементный массив.
Затем выделяется область памяти длямассива (либо корректно заданного, либо ошибочно), и ссылка на эту областьприсваивается переменной а. А переменная len (на которой основано свойство Length)устанавливается равной количеству элементов в массиве. Наконец, устанавливаютсязакрытые переменные lowerBound и upperBound.В классе RangeArray затем реализуются свойства Length и Error. Нижеприведены их определения.// Свойство Length, предназначенное только для чтения.public int Length {get {return len;}}// Свойство Error, предназначенное только для чтения.public bool Error {get {return errflag;}}Эти свойства аналогичны свойствам, используемым классом FailSoftArray, и ихработа организована подобным образом.Далее в классе RangeArray реализуется индексатор.
Вот его определение:// Это — индексатор для класса RangeArray.public int this[int index] {// Это — 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;} elseerrflag = true;Глава 10. Индексаторы и свойства275}}Этот индексатор очень похож на индексатор класса FailSoftArray, но с однимважным отличием. Обратите внимание на выражение, которое служит в качестве значенияиндекса массива а.index - lowerBoundЭто выражение преобразует реальный индекс, переданный через параметр index, в“нормальный”, т.е.
в значение, которое имел бы индекс текущего элемента, если быиндексирование массива начиналась с нуля. Ведь только такое индексирование подходитдля базового массива а. Это выражение работает при любом значении переменнойlowerBound: положительном, отрицательном или нулевом.Теперь осталось рассмотреть определение метода ok().// Метод возвращает значение true, если индекс// находится внутри границ.private bool ok(int index) {if(index >= lowerBound & index <= upperBound)return true;return false;}Это определение аналогично тому, которое используется в классе FailSoftArrayза исключением того, что попадание индекса в нужный диапазон проверяется с помощьюзначений переменных lowerBound и upperBound.Класс RangeArray иллюстрирует только один вид массива, создаваемого “подзаказ” с помощью индексаторов и свойств.
Можно также создавать динамические массивы(которые расширяются и сокращаются по необходимости), ассоциативные и разреженныемассивы. Попробуйте создать один из таких массивов в качестве упражнения.276Часть I. Язык C#Полныйсправочник поГлава 11НаследованиеНаследование — один из трех фундаментальных принципов объектноориентированного программирования, поскольку именно благодаря ему возможносоздание иерархических классификаций. Используя наследование, можно создать общийкласс, который определяет характеристики, присущие множеству связанных элементов.Этот класс затем может быть унаследован другими, узкоспециализированными классами сдобавлением в каждый из них своих, уникальных особенностей.В языке C# класс, который наследуется, называется базовым.
Класс, которыйнаследует базовый класс, называется производным. Следовательно, производный класс —это специализированная версия базового класса. В производный класс, наследующий всепеременные, методы, свойства, операторы и индексаторы, определенные в базовом классе,могут быть добавлены уникальные элементы.Основы наследованияC# поддерживает наследование, позволяя в объявление класса встраивать другойкласс. Это реализуется посредством задания базового класса при объявлении производного.Лучше всего начать с примера.
Рассмотрим класс TwoDShape, в котором определяютсяатрибуты “обобщенной” двумерной геометрической фигуры (например, квадрата,прямоугольника, треугольника и т.д.).// Класс двумерных объектов.class TwoDShape {public double width;public double height;}public void showDim() {Console.WriteLine("Ширина и высота равны " +width + " и " + height);}Класс TwoDShape можно использовать в качестве базового (т.е. как стартовуюплощадку) для классов, которые описывают специфические типы двумерных объектов.Например, в следующей программе класс TwoDShape используется для выведения классаTriangle. Обратите внимание на то, как объявляется класс Triangle.// Простая иерархия классов.using System;// Класс двумерных объектов.class TwoDShape {public double width;public double height;}public void showDim() {Console.WriteLine("Ширина и высота равны " +width + " и " + height);}// Класс Triangle выводится из класса TwoDShape.class Triangle : TwoDShape {public string style; // Тип треугольника.278Часть I.