Рейтинговые книги
Читем онлайн Интернет-журнал 'Домашняя лаборатория', 2007 №9 - Журнал «Домашняя лаборатория»

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 383 384 385 386 387 388 389 390 391 ... 415
конфигурации, то вызов метода игнорируется.

На методы, для которых возможно задание атрибута Conditional, накладывается ряд ограничений. Метод не должен быть:

• функцией, возвращающей значение;

• методом интерфейса;

• методом с модификатором override. Возможно его задание для virtual-метода. В этом случае атрибут наследуется методами потомков.

Атрибут Conditional, обычно с аргументом DEBUG, сопровождает модули, написанные для целей отладки. Но использование этого атрибута не ограничивается интересами отладки. Зачастую проект может использоваться в нескольких вариантах, например, в облегченном и более сложном. Методы, вызываемые в сложных ситуациях, например, ComplexMethod, имеющий атрибут условной компиляции, будут вызываться только в той конфигурации, где определена константа COMPLEX.

Приведу пример работы с отладочными методами. Рассмотрим класс, в котором определены три метода, используемые при отладке:

public class DebugPrint

{

   [Conditional("DEBUG")] static public void

       PrintEntry(string name)

   {

       Console.WriteLine("Начал работать метод " + name);

    }

    [Conditional("DEBUG")] static public void

        PrintExit(string name)

    {

        Console.WriteLine("Закончил работать метод " + name);

     }

     [Conditional("DEBUG")]

         static public void PrintObject(object obj, string name)

     {

         Console.WriteLine("Объект {0}: {1}", name,

             obj.ToString ());

     }

}

В классе Testing определено поле класса:

int state = 1;

и группа методов:

public void TestDebugPrint ()

{

    DebugPrint.PrintEntry("Testing.TestDebugPrint");

    PubMethod ();

    DebugPrint.PrintObj ect(state, "Testing.state");

    DebugPrint.PrintExit("Testing.TestDebugPrint");

}

void InMethod1()

{

    DebugPrint.PrintEntry("InMethod1");

    // body

    DebugPrint.PrintExit("InMethod1");

}

void InMethod2()

{

    DebugPrint.PrintEntry("InMethod2");

    // body

    DebugPrint.PrintExit("InMethod2");

}

public void PubMethod()

{

   DebugPrint.PrintEntry("PubMethod");

   InMethod1 ();

   state++;

   InMethod2 ();

   DebugPrint.PrintExit("PubMethod");

}

Этот пример демонстрирует трассировку хода вычислений, для чего в начало и конец каждого метода вставлены вызовы отладочных методов, снабжающие нас информацией о ходе вычислений. Такая трассировка иногда бывает крайне полезной на этапе отладки, но, естественно, она не должна присутствовать в финальной версии проекта. Взгляните на результаты, полученные при вызове метода TestDebugPrint в конфигурации Debug.

Рис. 23.1. Трассировка вычислений в процессе отладки

При переходе к конфигурации Release отладочная информация появляться не будет.

Классы Debug и Trace

Атрибут условной компиляции Conditional характеризует метод, но не отдельный оператор. Иногда хотелось бы иметь условный оператор печати, не создавая специального метода, как это было сделано в предыдущем примере. Такую возможность и многие другие полезные свойства предоставляют классы Debug и Trace.

Классы Debug и Trace — это классы-двойники. Оба они находятся в пространстве имен Diagnostics, имеют идентичный набор статических свойств и методов с идентичной семантикой. В чем же разница? Методы класса Debug имеют атрибут условной компиляции с константой DEBUG, действуют только в Debug-конфигурации проекта и игнорируются в Release-конфигурации. Методы класса Trace включают два атрибута Conditional с константами DEBUG и TRACE и действуют в обеих конфигурациях.

Одна из основных групп методов этих классов — методы печати данных: Write, WriteIF, WriteLine, WriteLineIF. Методы перегружены, в простейшем случае позволяют выводить некоторое сообщение. Методы со словом If могут сделать печать условной, задавая условие печати в качестве первого аргумента метода, что иногда крайне полезно. Методы со словом Line дают возможность дополнять сообщение символом перехода на новую строку.

По умолчанию методы обоих классов направляют вывод в окно Output. Однако это не всегда целесообразно, особенно для Release-конфигурации. Замечательным свойством методов классов Debug и Trace является то, что они могут иметь много "слушателей", направляя вывод каждому из них. Свойство Listeners этих классов возвращает разделяемую обоими классами коллекцию слушателей — TraceListenerCollection. Как и всякая коллекция, она имеет ряд методов для добавления новых слушателей: Add, AddRange, Insert — и возможность удаления слушателей: Clear, Remove, RemoveAt и другие методы. Объекты этой коллекции в качестве предка имеют абстрактный класс TraceListener. Библиотека FCL включает три неабстрактных потомка этого класса:

• DefauitTraceListener — слушатель этого класса, добавляется в коллекцию по умолчанию, направляет вывод, поступающий при вызове методов классов Debug и Trace, в окно Output;

• EventLogTraceListener — посылает сообщения в журнал событий Windows;

 TextWriterTraceListener — направляет сообщения объектам класса TextWriter или Stream; обычно один из объектов этого класса направляет вывод на консоль, другой — в файл.

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

Помимо свойства Listeners и методов печати, классы Debug и Trace имеют и другие важные методы и свойства:

• Assert и Fail, проверяющие корректность хода вычислений — о них мы поговорим особо;

• Flush — метод, отправляющий содержание буфера слушателю (в файл, на консоль и так далее). Следует помнить, что данные буферизуются, поэтому применение метода Flush зачастую необходимо, иначе метод может завершиться, а данные останутся в буфере;

• AutoFiush — булево свойство, указывающее, следует ли после каждой операции записи данные из буфера направлять в соответствующий канал. По умолчанию свойство выключено, и происходит только буферизация данных;

 Сlose — метод, опустошающий буфера и закрывающий всех слушателей, после чего им нельзя направлять сообщения.

У классов есть и другие свойства и методы, позволяющие, например, заниматься структурированием текста сообщений.

Рассмотрим пример работы, в котором отладочная информация направляется в разные каналы — окно вывода, консоль, файл:

public void Optima()

{

    double х, у=1;

    х= у — 2*Math.Sin(у);

    FileStream f = new FileStreamCDebuginfo.txt",

        FileMode.Create, FileAccess.Write);

    TextWriterTraceListener writer1 =

        new TextWriterTraceListener(f);

    TextWriterTraceListener writer2 =   

        new TextWriterTraceListener(System.Console.Out);

    Trace.Listeners.Add(writer1);

    Debug.Listeners.Add (writer2);

    Debug.WriteLine("Число слушателей: " +

       Debug.Listeners.Count);

    Debug.WriteLine("автоматический вывод из буфера: "+

       Trace.AutoFiush);

    Trace. WriteLinelf (x<0, "Trace: " + "x= " + x.ToString()

       + " у = " + y);

    Debug. WriteLine (" Debug: " + "x= " + x.ToString() +

      " у = " + у);

    Trace.Flush();

    f. Close();

}

В коллекцию слушателей вывода к слушателю по умолчанию добавляются еще два слушателя класса TextWriterTraceListener. Заметьте, что хотя они добавляются

1 ... 383 384 385 386 387 388 389 390 391 ... 415
На этой странице вы можете бесплатно читать книгу Интернет-журнал 'Домашняя лаборатория', 2007 №9 - Журнал «Домашняя лаборатория» бесплатно.
Похожие на Интернет-журнал 'Домашняя лаборатория', 2007 №9 - Журнал «Домашняя лаборатория» книги

Оставить комментарий