ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 3280

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

д о л ж ен выводить строку, возвращаемую T o S t r i n g ( ) , отсутствует. То есть в функцию передано значение для него, но сам элемент забыт. Чтобы исправить ошибку, две коман­

д ы W r i t e L i n e ( )

надо переписать следующим образом:

/ / d i s p l a y t h e

t w o s t u d e n t s

 

C o n s o l e . W r i t e L i n e ( " S t u d e n t

1 = { o } " ,

s i . T o S t r i n g ( ) ) ;

C o n s o l e . W r i t e L i n e ( " S t u d e n t

2 = { o } " ,

s 2 . T o S t r i n g ( ) ) ;

Рис. 21.18. Возвращаемое значение корректно. Так что же происходит?

Вероятно, ошибка произошла в

результате перепутывания двух видов функций

W r i t e L i n e ( ) :

 

 

 

 

/ / С и с п о л ь з о в а н и е м у п р а в л я ю щ е г о э л е м е н т а

C o n s o l e . W r i t e L i n e ( " S t u d e n t

1

=

" +

s i . T o S t r i n g ( ) ) ' ;

/ / С и с п о л ь з о в а н и е м у п р а в л я ю щ е г о э л е м е н т а

C o n s o l e . W r i t e L i n e ( " S t u d e n t

1

=

{ о } " ,

s i . T o S t r i n g ( ) ) ;

Подсказка о данных

Сейчас самое время рассказать об одном очень ценном нововведении в отладчике Visual Studio 2005: подсказке о данных (DataTip). Такая подсказка представляет собой небольшой прямоугольник, который появляется, когда вы останавливаете курсор над пе­ ременной во время останова в отладчике. После того как я дважды нажал <F10> для воз­ врата в функцию M a i n ( ) , я помещаю курсор над переменной si внутри вызова W r i t e ­ L i n e () (без щелчка) и вижу появившееся окошко с si и его значением T o S t r i n g ( ) : { S t u d e n t ID ( 1 ) }. Я игнорирую маленький квадратик, происхождение которого из-за введенного символа табуляции я пояснял ранее. Информацию о подсказке о данных можно получить из раздела "DataTip" справочной системы.

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

Глава 21. Использование интерфейса Visual Studio

519


Теперь о существенном усовершенствовании подсказок, видном из рис. 21.19. По­ местите курсор мыши над знаком + в окошке s l . При этом откроется детальная инфор­

мация об объекте s l . Если вы переместите курсор на значок

+ перед S t a t i c

m e m b e r s , а п о т о м — перед a l l S t u d e n t s , а з а т е м — перед [0]

— нулевым членом

A r r a y L i s t объекта a l l S t u d e n t s — то вы опять увидите sl — в этот раз уже внутри A r r a y L i s t объекта a l l S t u d e n t s .

Рис. 21.19. Подсказка о данных— отличное средство, чтобы быстро разо­ браться с содержимым объекта в отладчике

Подсказки позволяют погружаться все глубже и глубже в сложные объекты. (Ранее для получения этой информации необходимо было открывать окно Watch или QuickWatch для данной переменной, либо использовать окно Locals.)

Снова щелкните на красном кружке (см. рис. 21.17) для того, чтобы удалить точку останова. (Вы можете также воспользоваться командой меню D e b u g s

Delete All Breakpoints.) В меню Debug имеется еще одна команда D e b u g s

Windows1 ^Breakpoints, которая предоставляет доступ ко всем возможностям точек останова.

Стек вызовов

Далее я ставлю точку останова на вызове O u t p u t A l l S t u d e n t s ( ) , следующем не­ посредственно за двумя только что исправленными вызовами W r i t e L i n e ( ) . Я нажи­ маю <F5> для выполнения программы до этой точки и смотрю, что выведено в окне Console. Все выглядит как надо.

Затем я еще раз нажимаю <F10>, чтобы пропустить вызов O u t p u t A l l S t u d e n t s ( ) . И вот тут-то это и происходит.

Появляется сообщение об ошибке наподобие показанного на рис. 21.20. Оно привя­ зано к строке с циклом f o r , а именно к условию цикла, в котором вызывается свойство C u r r e n t итератора (об итераторах см. главу 20, "Работа с коллекциями"). Сообщение о б ошибке гласит: E n u m e r a t i o n h a s n o t s t a r t e d . C a l l M o v e N e x t (Перечисление не начато. Вызовите M o v e N e x t ) —- все, что следует знать о происшедшем.

520

Часть VII. Дополнительные главы


Рис. 21.20. Visual Studio говорит о том, что забыт начальный вызов MoveNext ()

Я закрываю окно сообщения об ошибке и, чтобы получить немного дополнительной информации, командой меню D e b u g O W i n d o w s ^ C a l l Stack открываю окно стека вызо­ вов Call Stack, показанное на рис. 21.21 (здесь оно раскрыто для того, чтобы было луч­ ше видно представленную им информацию).

Puc; 21.21. Окно Call Stack полезно при поиске источника фатальной

ошибки

и для определения вашего местоположения

 

Глава 21. Использование интерфейса Visual Studio

521

Здесь содержится вся информация, которую может предоставить отладчик — и, как правило, ее достаточно много. Желтая стрелка и подцветка в окне редактора указывают на выражение, вызвавшее проблемы. Окно Call Stack описывает, как именно мы попали в точку генерации исключения: функция Main() вызвала OutputAllStudents () в строке 64. Информация о номерах строк в полосе состояния говорит, что строка 64 — это заголовок цикла for, который уже был указан окном с сообщением об ошибке.

Вы можете вывести номера строк в окне редактирования — для этого воспользуй­ тесь командой меню Tools^OptionsOEditor^C* и выберите Line Numbers.

В данном случае стек вызовов не оказывает особой помощи, так как включает только две функции: Main() и OutputAllStudents ( ) . Но в больших программах может быть очень сложно обнаружить, как именно вы попали в эти жернова — и стек вызовов окажет вам в таком случае неоценимую помощь.

Дополнительную информацию можно получить, щелкнув на ссылке View Detail в ок­ не сообщения об исключении и воспользовавшись полем InnerException (единственное со знаком + перед ним). Поместите курсор над StackTrace и получите дополнительную информацию. В верхней строке содержится фраза get_Current. Вот где настоящая неприятность — в вызове свойства Current итератора.

Беглый взгляд на документацию по свойству IEnumerator. Current проясняет, что не вызван метод MoveNext () перед попыткой получения первого элемента. Теперь, когда стало понятно, в чем дело, следует остановить отладчик щелчком на кнопке Stop Debugging в полосе инструментов Debug и вернуться в режим редактирования. (Кнопка панели инструментов — это ярлык команды меню Debug^Stop Debugging; аналогич­ ного эффекта можно добиться и с помощью клавиш <Shift+F5>.)

В этот момент у меня накапливается несколько симптомов, указывающих на свойство Current итератора. Исключение подцвечивает условие цикла for,

где вызывается Current, StackTrace в InnerException также упомина­ ет закулисное имя Current — get_Current. (Свойства в действительности реализуются за сценой с использованием методов с префиксами get_ или set_.) Итак, вопрос — что же такого могло начудить свойство Current? От­ вет — я не вызвал сначала MoveNext ( ) , так что свойство Current не полу­ чило начальное значение — первый элемент данных в ArrayList.

Дальнейшее исследование показывает, что весь цикл for — одна большая ошибка. Итератор завершает работу, когда MoveNext () возвращает false, а не когда Cur­ rent получает значение null. Обновленный цикл (теперь — более безопасный while) выглядит следующим образом:

public static void OutputAllStudents()

{

IEnumerator iter = allStudents.GetEnumerator(); while(iter.MoveNext()) // 'while1 , а не 'for'

{

Student s = (Student)iter.Current; Console.WriteLine("Student = {o}", s.ToString());

}

}

522

Часть VII. Дополнительные главы


Теперь программа использует MoveNext () для итераций по контейнеру объектов Student. Каждый Student возвращается свойством Current. Цикл завершает рабо­ ту, когда вызов MoveNext () возвращает false, что указывает на то, что в коллекции больше нет не просмотренных элементов.

Цикл foreach также может помочь избежать описанных неприятностей—об­ ратитесь к материалу о блоках итераторов в главе 20, "Работа с коллекциями".

Я сделал это!

Очередной запуск программы наконец приводит к корректному выводу:

Эта программа не работает! Student 1 = Student 1 (1) Student 2 = Student 2 (2) Student = Student 1 (1) Student = Student 2 (2)

Нажмите <Enter> для завершения программы...

Хорошо, что главной в данной демонстрационной программе была ее отладка, а не создание красивого вывода... Кстати, первая строка вывода более не актуальна.

Исправленная версия демонстрационной программы хранится на прилагае­ мом компакт-диске под именем VSDebugFixed.

Не важно, насколько мощный инструмент отладчик — чем меньше вы будете к нему обращаться, тем лучше. Последние веяния в программировании, такие как первоначаль­ ная разработка тестов, непрерывный рефакторинг, шаблоны проектирования и другие аспекты того, что именуется "экстремальным" программированием, могут существенно снизить количество времени, проводимое в отладчике, и повысить производительность программирования (не говоря об уменьшении количества седины у программиста). По­ ищите литературу или информацию в Web, посвященную вопросам экстремального про­ граммирования.

Visual Studio — очень богатая среда программирования, часто способная выполнить одну задачу разными способами. Многие возможности наверняка не дождутся, когда вы их примените. Но чем больше вы знаете о них, тем более эффективно вы сможете вы­ полнять свою работу в качестве программиста на С#.

Даже если вы используете Visual Studio, все равно стоит прочесть главу 22, "С# по дешевке", в которой рассматриваются альтернативы Visual Studio. Это только углубит ваше понимание среды программирования на С#.

ше главы

Глава 21. Использование интерфейса Visual Studio

523