Метод Флойда и утверждения Assert
Лет двадцать назад большие надежды возлагались на формальные методы доказательства правильности программ, позволяющие доказывать корректность программ аналогично доказательству теорем. Реальные успехи формальных доказательств невелики. Построение такого доказательства не проще написания корректной программы, а ошибки столь же возможны и часты, как и ошибки программирования. Тем не менее, эти методы оказали серьезное влияние на культуру проектирования корректных программ, появление в практике программирования понятий предусловия и постусловия, инвариантов и других важных понятий.
Одним из методов доказательства правильности программ был метод Флойда, при котором программа разбивалась на участки, окаймленные утверждениями - булевскими выражениями (предикатами). Истинность начального предиката должна была следовать из входных данных программы. Затем для каждого участка доказывалось, что из истинности предиката, стоящего в начале участка, после завершения выполнения соответствующего участка программы гарантируется истинность следующего утверждения - предиката в конце участка. Конечный предикат описывал постусловие программы.
Схема Флойда используется на практике, по крайней мере, программистами, имеющими вкус к строгим методам доказательства. Утверждения становятся частью программного текста. Само доказательство может и не проводиться: чаще всего у программиста есть уверенность в справедливости расставленных утверждений и убежденность, что при желании он мог бы провести и строгое доказательство. В C# эта схема поддерживается тем, что классы Debug и Trace имеют метод Assert, аргументом которого является утверждение. Что происходит, когда вычисление достигает соответствующей точки и вызывается метод Assert? Если истинно булево выражение в Assert, то вычисления продолжаются, не оказывая никакого влияния на нормальный ход вычислений. Если оно ложно, то корректность вычислений под сомнением, их выполнение приостанавливается и появляется окно с уведомлением о произошедшем событии, что показано на рис. 23.3.
Рис. 23.3. Нарушение утверждения Assert
В этой ситуации у программиста есть несколько возможностей:
- прервать выполнение, нажав кнопку Abort;
- перейти в режим отладки (Retry);
- продолжить вычисления, проигнорировав уведомление.
В последнем случае сообщение о возникшей ошибке будет послано всем слушателям коллекции TraceListenerCollection.
Рассмотрим простой пример, демонстрирующий нарушение утверждения:
public void WriteToFile(){ Stream myFile = new FileStream("TestFile.txt",FileMode.Create,FileAccess.Write); TextWriterTraceListener myTextListener = new TextWriterTraceListener(myFile); int y = Debug.Listeners.Add(myTextListener); TextWriterTraceListener myWriter = new TextWriterTraceListener(System.Console.Out); Trace.Listeners.Add(myWriter); Trace.AutoFlush = true; Trace.WriteLine("автоматический вывод из буфера:" + Trace.AutoFlush); int x = 22; Trace.Assert(x<=21, "Перебор"); myWriter.WriteLine("Вывод только на консоль"); //Trace.Flush(); //Вывод только в файл byte[] buf = {(byte)'B',(byte)'y'}; myFile.Write(buf,0, 2); myFile.Close();}
Как и в предыдущем примере, здесь создаются два слушателя, направляющие вывод отладочных сообщений на консоль и в файл. Когда произошло нарушение утверждения Assert, оно было проигнорировано, но сообщение о нем автоматически было направлено всем слушателям. Метод также демонстрирует возможность параллельной работы с консолью и файлом. На рис. 23.4 показаны результаты записи в файл:
Рис. 23.4. Файл с записью сообщения о нарушении утверждения Assert
Вариацией метода Assert является метод Fail, всегда приводящий к появлению окна с сообщением о нарушении утверждения, проверка которого осуществляется обычным программным путем.
23. Лекция: Отладка и обработка исключительных ситуаций
23.4