Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 57
Текст из файла (страница 57)
чек ! 11)оь(1пс)ек)) ( Глава (О. Индексаторы и свойства 291 Еггу1ад = Са1яет гегцгп а[гпбех]) ) е1зе ( Егге1ад = ггце) гегцгп 0; ) ) // Это аксессор зес. яег ( 1г(ох(1пбех)) ( а[гпбех] = ча1цет Егг71ад = Са1яет ) е1яе Еггу1ад = Ггце; ) // Возвратить логическое значение Ггце, если // индекс находится в установленных границах. рггчаге Ьоо1 о)<(1пг гпбех) ( 1г(1пбех >= 0 а 1пбех < Ьепдс)т) гесцгп Ггце; гекцгп Са1яе) ) // Продемонстрировать применение отказоустойчивого массива. с1аяя ЕБПешо ( ясас1с чо1с( Ма1п() ( еаг13оссйггау гя = пен еаг1аосглггау(5)т Ьпг хт // Выявить скрытые сбои.
Сопяо1е.ыг1геЬ1пе("Скрытый сбой.")~ гог(1пс к=От г < (гя.Ьепдгп * 2); г++) Сз[1] = 1*10т гог(1пс г=О; 1 < (гя.Ьепдсл * 2)т г++) ( х = Ее[1]) 1г(х (= -1) Сопяо1е.агаве(х + " ")) ) Сопяо1е.йг1сеЬ1пе()т // Л теперь показать сбои. Сопзо1е.ыг1сеЬ1пе("1псбой с уведомлением об ошибках."); сог(1пг г=о) 1 < (гя.ьепдг)т * 2)) 1++) [ ля[1] = 1*10) 11(вя.аггр1ад) сопяо1е.ыг1геьгпе("гз[" + г + "] вне границ" !) гог(1пг к=От г < (гя.ьепдгп * 2)т г++) ( 292 Часть ).
Езык С» х = Гя[1)т 11(! Гя.Еггт1яч) Сопяо1е.иг1ке(х + " ") т е1яе Сопяо1е.иг1ке11пе("Гя[" + 3. + ") вне границ"); Вот к какому результату приводит выполнение этой программы: Скрытый сбой. 0 10 20 30 40 0 0 0 0 0 Сбой с уведомлением об ошибках. Гя[5) вне границ Гя[б! яне границ Гя[7! яне границ Гя[8) яне границ Гя(9] вне границ 0 10 20 ЗО 40 Гя[5! вне границ Гя(б! вне границ Гя[7) яне границ Ге[8] яне границ Гя[9! яне границ Иидексатор препятствует нарушению границ массива. Внимательно проанализируем каждую часть кода иидексатора.
Ои начинается со следующей строки: рцъггс 1пг Скья[1пс 1пбех! ( В этой строке кода объявляется иидексатор, оперирующий злемеитами типа 1пс. Ему передается индекс в качестве параметра 1пбех. Кроме того, индексатор объявляется открытым грц)711с), что дает возможность использовать этот иидексатор в коде за пределами его класса. Рассмотрим код аксессора алекс Оег ( 11(ох(1пбех)) ( Еггт1ач = Га1яет гекцгп а[1пбех]т ) е1яе ( Еггт1ач = Сгцет гекцгп 0; ) ) Аксессор оес предотвращает ошибки нарушения границ массива, проверяя в первую очередь, находится ли индекс в установленных границах.
Зта проверка граииц выполияется в методе о)к ( ), который возвращает логическое значение С гце, если индекс правильиый, в противном случае — логическое значение Га1яе. Так, если указанный индекс иахояится в установленных границах, то по этому индексу возвращается соответствующий злемеит. А если индекс оказывается вие установленных границ, то никаких операций ие производится, ио в то же время ие возникает никаких ошибок переполнения. В данном варианте класса Га115о г т йгта у переменная еггр1ао содержит результат каждой операции. Ее содержимое может быть проверено после каждой операции иа предмет удачного Глава!О, Индексвторы и свойства 293 или неудачного выполнения последней.
ГВ главе 13 будет представлен более совершенный способ обработки ошибок с помощью имеющейся в С(т подсистемы обработки исключительных ситуаций, а до тех пор можно вполне обойтись установкой и анализом признака ошибки.) А теперь рассмотрим код аксессора зес, предотвращающего ошибки нарушения границ массива: зев ( аг(ов(1пбех)) ( а[1пбех] = ча1цет Еггт1ад = Га1вет ) е1зе Еггр1ад = Сгцет ) Если параметр 1пк)ех метода о)т () находится в установленных пределах, то соответствуюшему элементу массива присваивается значение, передаваемое из параметра ча1це. В противном случае устанавливается логическое значение ьгце переменной ЕхгР1ад.
Напомним, что уа1це в любом аксессорном методе является неявным параметром, содержащим присваиваемое значение. Его не нужно (да и нельзя) объявлять отдельно. Наличие обоих аксессоров, сес и зес, в индексаторе не является обязательным. Так, можно создать индексатор только для чтения, реализовав в нем один лишь аксессор сес, или же индексатор только для записи с единственным аксессором зес. Перегрузка индексаторов Индексатор может быть перегружен. В этом случае для выполнения выбирается тот вариант индексатора, в котором точнее соблюдается соответствие его параметра и аргумента, указываемого в качестве индекса.
Ниже приведен пример программы, в которой индексатор массива класса ра11$отсдггау перегружается для индексов типа боцЬ1е. При этом индексатор типа боцЬ1е округляет свой индекс до ближайшего целого значения. // Перегрузить индексатор массива класса Еа11$остаггау. цяьпп Яуаоезт с1аяа Еа11$откхггау ( гпо[) а) // ссылка на базовый массив рцЬ11с 1пв ЬепдСЬ) // открытая переменная длины массива рцЬ11с Ьоо1 Еггр1апт // обозначает результат последней операции // Построить массив заданного размера. рцьтгс Ра11$осввггау(1пс яьге) ( а = пен ьпк[аьге]т Ьеппвп = а1гет ) // Это индексатор типа 1пв для массива Еа11$откаггау.
рцьтьс гпк СЬ1в(1пс 1пбех] ( // Это аксессор Пес. 294 Часть (. Язык С() дег ( 15(о)с(1пбех)) ( ЕггГ1ад = га1ве) ' гегцгп а[гпбех]; ) е1ве ( ЕггГ1ад = Ггце) гегцгп 0; ) ) // Зто аксессор вег. вег ( 15(о)т(апбех)) а[1пбех] = ча1це) ЕггГ1ад = га1вет ! е1ве ЕггГ1ад = Ггце) ) ) /* Зто еше один индексатор для массива Га115оусйггау. Он округляет свой аргумент до ближайшего целого индекса. */ рцб11с гпс Гнгв(боцб1е Ебх] ( // Это аксессор дег. дег ( Епг 1пбех) // Округлить до ближайшего целого. 15( (гбх — (1пс) гбх) < 0.5) 1пбех (1пг) гбх) е1ве 1пбех = (1пс) гбх + 1; Ег(ох(ьпт)ех)) ( ЕггГ1ад = Га1вет гесцгп а[1пбех]) ) е1ве ( ЕггГ1ад = Сгце) гегцгп О) ) ) // Это аксессор вес.
вег ( Епг ьпбехт // Округлить до ближайшего целого. гй( (гбх - (1 б) гбх) < 0.5) Епбех = (Епс) гбх; е1ве апбех = (1пс) Ебх + 1) ].Г(оа(1пбех)) ( а(1пбех] уа1це) ЕггГ1ад = Га1ве) ) Глава )О. Индвксвторы и свойства 295 е1зе Кггг1ао = Ггцет ) ) // Возвратить логическое значение Ггое, если // индекс находится в установленных границах. рггчасе Ьоо1 ов(1пс 1пбех) ( 16(гпбех >= О а 1пбех < Ьепосп) гесцгп Ггце) гесцгп Га1яе) ) // Продемонстрировать применение отказоустойчивого // массива.
с1азя Гзпещо ( ясакгс чо1С Ма1п 0 ( Га11эоесйггау Гя = пен Гаг1эовгйггау(5)) // Поместить ряд значений в массив Гз. Гог(1пк г=о; 1 < Гя.Ьепдспт 1++) Гз (1] // й теперь воспользоваться индексами // типа 1пс и боцьве для обращения к массиву. Сопзо1е.нг[геЬ1пе("Гя(1): " + Гз(1]); Сопяо1е.иг1сеЬ[пе("Гз(2]: " + Гз[2]); сопяо1е.игггеь1пе("гз(1.1]: " + гя(1.1))т Сопяо1е.нггке1гпе("Гя(1.6): " + Гз[1.6])) ) ) При выполнении этой программы получается следующий результат: ля[1]к 1 Гз(2]: 2 Гя(1.1]: 1 Гя(1.6]к 2 Как показывает приведенный выше результат, индексы типа с) опЬ1е округляются до ближайшего целого значения.
В частности, индекс 1. 1 округляется до [, а индекс 1. 6 — до 2. Представленный выше пример программы наглядно демонстрирует правомочность перегрузки индексаторов, но на практике она применяется нечасто. Как правило, индексаторы перегружаются для того, чтобы использовать объект определенного класса в качестве индекса, вычисляемого каким-то особым образом. Индексаторы без базового массива Следует особо подчеркнуть, что индексатор совсем не обязательно должен оперировать массивом.
Его основное назначение — предоставить пользователю функциональные возможности, аналогичные массиву. В качестве примера в приведенной ниже программе демонстрируется индексатор, выполняющий роль массива только для чтения, содержащего степени числа 2 от О до [5. Обратите внимание на то, что в этой программе от- 296 Часть ). Язык Са сутствует конкретный массив. Вместо этого иидексатор просто вычисляет подходящее значение для заданного индекса.
// Нндексаторы совсем не обязательно должны // оперировать отдельными массивами. пя1пч Зуясевп с1аяя РнгОЕТно ( /* доступ к логическому массиву, содержашему степени числа 2 от 0 до 15. */ рпб11с гпс Гная[гпс 1пбех] ( // вычислить и возвратить степень числа 2. дег ( Ее((1пбех >= 0) ьа (Епбех < 16)) гегпгп рнг(1пбех) е1яе гесдгп -1г ) // Аксессор яес отсутствует. ) 1пс риг(1пс Р) ( Епс геяи1Г = 1) Еог(гпс 1=От 1 < р; 1++) геяп1Г * 2) гегпгп геяп1гт ) с1аяя ОяернгОЕТно ( ясас1с гоаб Иа1п О ( РигОЕТно рнг = пеи РигОЕТно(); Сопяо1е.нггсе("Первые 8 степеней числа 2: ")) Еог(гпс 1 О) г < 8) 1е.ь) Сопяо1е.Итаке(рнг[1) 4 " ")/ Сопяо1е.нгасевапе()/ Сопяо1е.иг1се("А зто некоторые ошибки: ")т Сопяо1е.нг1се(рнг(-1) + " " + рнг(17))) Сопяо1е. Иг1се11пе () т ) ) Вот к какому результату приводит выполнение этой программы: Первые 8 степеней числа 2: 1 2 4 8 16 52 64 128 А это некоторые ошибки: -1 -1 Обратите внимание на то, что в индексатор класса РмгОЕТно включен только аксессор дес, но в нем отсутствует аксессор з е г.
Как пояснялось выше, такой индексатор служит только для чтения. Следовательно, объект класса РигОЕТио может указываться только в правой Глава )О. Индексвторы и свойства 297 части оператора присваивания, но не в левой его части. Например, попытка ввести следую- щую строку кода в приведенную выше программу не приведет к желаемому результату: рнг[01 = 11/ // не подлежит компиляции Такой оператор присваивания станет причиной появления ошибки во время компиляции, поскольку для индексатора не определен аксессор ьев. На применение индексаторов накладываются два существенных ограничения. Вопервых, значение, выдаваемое индексатором, нельзя передавать методу в качестве параметра геЕ или оцс, поскольку в индексаторе не определено место в памяти для его хранения.