Здесь содержится вся информация, которую может предоставить отладчик — и, как правило, ее достаточно много. Желтая стрелка и подцветка в окне редактора указывают на выражение, вызвавшее проблемы. Окно 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());
}
}