Assert Yourself

The .NET framework provides a Debug class to help debug your code. One of the most powerful methods in this class is Assert. This method is static and returns void in C#, and is a shared sub in VB.NET.

An Assert statement both documents what you believe is happening in your code at any given moment and forces an error and notification if that assumption is incorrect.

.NET provides both a Debug.Assert statement and a Trace.Assert method. Debug methods are removed from your code in release mode, but Trace methods are not (or can be toggled on and off from configuration files (see Chapter 22).

You can see a good (if contrived) use of the Assert statement by adding a third menu choice, "menuTestDivsion," whose event handler is shown here:

figs/csharpicon.gif

private void menuTestDivision_Click(
 object sender, System.EventArgs e)
{
 Employee joe = new Employee("Joe",47,5);
 Double pctgOfLife = joe.Age / joe.YearsOfService;
 lblDisplay.Text = 
 joe.Name + 
 " has worked here for " +
 pctgOfLife + "% of his life!";
}

When you run this code and choose the Test Division menu choice, you learn that Joe has worked at the company for 9 percent of his life. What happens, however, if the value passed in as years of service is 0. You will then divide 47 by 0, which is illegal, and your program will crash.

The right approach is to test for zero years of service, and if it is found, to skip the division. Assume for a moment, however, that you have other code that prohibits creating a user with zero years of service. Is it now safe to proceed with the division? In theory, yes. But to quote Pat Johnson one more time, "In theory, theory and practice are the same, but in practice they never are."

To ensure that your assumptions are correct, you may want to assert that the years of service cannot be zero. Do so by using the Debug.Assert method with up to three arguments. The first argument is mandatory: the condition you wish to assert:

figs/csharpicon.gif

private void menuTestDivision_Click(
 object sender, System.EventArgs e)
{
 Employee joe = new Employee("Joe",47,0);
 Debug.Assert(joe.YearsOfService != 0);

If you run this code, when the Assert fails (as it will in this case), you are presented with an Assertion failure window, shown in Figure 21-24, which provides a stack trace and the ability to ignore the failure, retry the condition, or abort the program.

Figure 21-24. Assertion failure

figs/pnwa_2124.gif

You are free to add two more parameters: a short string and a longer description:

figs/csharpicon.gif

Debug.Assert(joe.YearsOfService != 0,
 "Age can not be zero!",
 "It was expected that the age of an employee could never be zero");

If you do, the Assert window will display this additional information, as shown circled in Figure 21-25.

Figure 21-25. Assert failedadditional information

figs/pnwa_2125.gif

21.6.1 Side effects

When using Debug statements, take care to not set any values or otherwise change the state of your program within the Assert statement. When you recompile into Release mode, the Debug Assertions and other statements are removed from your programs, and these side effects will be removed as well, which can result in confusing bugs ("every time I put this in the debugger, it works fine, but when I release the code...").

21.6.1.1 Trace versus Debug

The key difference between Trace and Debug is that Trace is enabled (by default) both in debug and release mode, while Debug is enabled (by default) only in Debug mode. This difference allows you to decide what debugging statements make it into your release code. (Note that Trace statements take up room in your release code even if you disable them, unless you do not compile them into your program by undefining the TRACE symbol.)

21.6.1.2 Trace and Debug methods

The Trace and Debug classes have many useful methods in addition to Assert. Each method is static and void (in C#) or shared sub in VB.NET. The most important methods are listed in Table 21-4.

Table 21-4. Trace and Debug methods

Method

Description

Assert

Overloaded. Tests a condition and displays a message.

Fail

Like Assert but doesn't test a conditionjust displays a message.

Indent

Increases the indentation level in the output by one (for organizing output).

Unindent

Decreases the indentation level by one.

Write/WriteLine

Overloaded method that writes extensive debug information to the listeners in the Listeners collection. WriteLine version adds a new line at the end.

WriteIf/WriteLineIf

Like Write, but writes only if a condition is met.

21.6.2 Listeners

A powerful alternative to displaying error messages is capturing errors to log files. To do this you will need to add a Listener to your program.

Listeners can listen to both Debug and Trace classes. You will find three types of predefined listeners:

TextWriterListener

Redirects its output to an instance of the TextWriter class or to any Stream class. This listener can also write to the console or to a file because both are Stream objects.

EventLogListener

Emits Write/WriteLine messages to an Event log.

DefaultTraceListener

Emits Write and WriteLine messages to the OutputDebugString and to the Debugger.Log method. If you want a listener besides (or instead of) the DefaultTraceListener to receive Debug and Trace output, you must explicitly add it to the Listeners collection.

For example, you can change the Test Division code to write to a custom log with these lines of code:

figs/csharpicon.gif

private void menuTestDivision_Click(
 object sender, System.EventArgs e)
{
 Employee joe = new Employee("Joe",47,0);
 
 Trace.Listeners.Clear( ); // clear all listeners
 Trace.Listeners.Add(new EventLogTraceListener("BugRiddenLog"));
 
 Debug.Assert(joe.YearsOfService != 0,
 "Age can not be zero!",
 "It was expected that the age of an employee could never be zero");
 if ( joe.YearsOfService != 0 )
 {
 Double pctgOfLife = joe.Age / joe.YearsOfService;
 lblDisplay.Text = 
 joe.Name + 
 " has worked here for " +
 pctgOfLife + "% of his life!";
 }
}

Notice that you've encased the actual division in a test so you do not fire an exception. When you run this code, nothing appears to happen. To see the actual log, go to Start AdministrativeTools EventViewer and click on ApplicationLog. You'll find an entry with a source of BugRiddenLog, and if you double-click on it, you'll find your log entry, as shown in Figure 21-26.

Figure 21-26. Event log

figs/pnwa_2126.gif

Windows Forms and the .NET Framework

Getting Started

Visual Studio .NET

Events

Windows Forms

Dialog Boxes

Controls: The Base Class

Mouse Interaction

Text and Fonts

Drawing and GDI+

Labels and Buttons

Text Controls

Other Basic Controls

TreeView and ListView

List Controls

Date and Time Controls

Custom Controls

Menus and Bars

ADO.NET

Updating ADO.NET

Exceptions and Debugging

Configuration and Deployment



Programming. NET Windows Applications
Programming .Net Windows Applications
ISBN: 0596003218
EAN: 2147483647
Year: 2003
Pages: 148

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net