Лет двадцать назад большие надежды возлагались на формальные методы доказательства правильности программ, позволяющие доказывать корректность программ аналогично доказательству теорем. Реальные успехи формальных доказательств невелики. Построение такого доказательства не проще написания корректной программы, а ошибки столь же возможны и часты, как и ошибки программирования. Тем не менее, эти методы оказали серьезное влияние на культуру проектирования корректных программ, появление в практике программирования понятий предусловия и постусловия, инвариантов и других важных понятий.
Одним из методов доказательства правильности программ был метод Флойда, при котором программа разбивалась на участки, окаймленные утверждениями — булевскими выражениями (предикатами). Истинность начального предиката должна была следовать из входных данных программы. Затем для каждого участка доказывалось, что из истинности предиката, стоящего в начале участка, после завершения выполнения соответствующего участка программы гарантируется истинность следующего утверждения — предиката в конце участка. Конечный предикат описывал постусловие программы.
Схема Флойда используется на практике, по крайней мере, программистами, имеющими вкус к строгим методам доказательства. Утверждения становятся частью программного текста. Само доказательство может и не проводиться: чаще всего у программиста есть уверенность в справедливости расставленных утверждений и убежденность, что при желании он мог бы провести и строгое доказательство. В C# эта схема поддерживается тем, что классы
Рис. 23.3.
В этой ситуации у программиста есть несколько возможностей:
• прервать выполнение, нажав кнопку Abort;
• перейти в режим отладки (Retry);
• продолжить вычисления, проигнорировав уведомление.
В последнем случае сообщение о возникшей ошибке будет послано всем слушателям коллекции
Рассмотрим простой пример, демонстрирующий нарушение утверждения:
public void WriteToFile()
{
Stream myFile = new
FileStream("TestFile.txt",FileMode.Create,FileAccess.Write);
TextWriterTraceListener myTextListener =
new TextWriterTraceListener(myFile); int у = 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)'В;(byte)'у'};
myFile.Write(buf,0, 2);
myFile.Close ();
}
Как и в предыдущем примере, здесь создаются два слушателя, направляющие вывод отладочных сообщений на консоль и в файл. Когда произошло нарушение утверждения
Рис. 23.4.
Вариацией метода
Классы