- •Contents
- •What Is C#?
- •C# Versus Other Programming Languages
- •Preparing to Program
- •The Program Development Cycle
- •Your First C# Program
- •Types of C# Programs
- •Summary
- •Workshop
- •C# Applications
- •Basic Parts of a C# Application
- •Structure of a C# Application
- •Analysis of Listing 2.1
- •Object-Oriented Programming (OOP)
- •Displaying Basic Information
- •Summary
- •Workshop
- •Variables
- •Using Variables
- •Understanding Your Computer’s Memory
- •C# Data Types
- •Numeric Variable Types
- •Literals Versus Variables
- •Constants
- •Reference Types
- •Summary
- •Workshop
- •Types of Operators
- •Punctuators
- •The Basic Assignment Operator
- •Mathematical/Arithmetic Operators
- •Relational Operators
- •Logical Bitwise Operators
- •Type Operators
- •The sizeof Operator
- •The Conditional Operator
- •Understanding Operator Precedence
- •Converting Data Types
- •Understanding Operator Promotion
- •For Those Brave Enough
- •Summary
- •Workshop
- •Controlling Program Flow
- •Using Selection Statements
- •Using Iteration Statements
- •Using goto
- •Nesting Flow
- •Summary
- •Workshop
- •Introduction
- •Abstraction and Encapsulation
- •An Interactive Hello World! Program
- •Basic Elements of Hello.cs
- •A Few Fundamental Observations
- •Summary
- •Review Questions
- •Programming Exercises
- •Introduction
- •Essential Elements of SimpleCalculator.cs
- •A Closer Look at SimpleCalculator.cs
- •Simplifying Your Code with Methods
- •Summary
- •Review Questions
- •Programming Exercises
- •Introduction
- •Lexical Structure
- •Some Thoughts on Elevator Simulations
- •Concepts, Goals and Solutions in an Elevator Simulation Program: Collecting Valuable Statistics for Evaluating an Elevator System
- •A Deeper Analysis of SimpleElevatorSimulation.cs
- •Class Relationships and UML
- •Summary
- •Review Questions
- •Programming Exercises
- •The Hello Windows Forms Application
- •Creating and Using an Event Handler
- •Defining the Border Style of the Form
- •Adding a Menu
- •Adding a Menu Shortcut
- •Handling Events from Menus
- •Dialogs
- •Creating Dialogs
- •Using Controls
- •Data Binding Strategies
- •Data Binding Sources
- •Simple Binding
- •Simple Binding to a DataSet
- •Complex Binding of Controls to Data
- •Binding Controls to Databases Using ADO.NET
- •Creating a Database Viewer with Visual Studio and ADO.NET
- •Resources in .NET
- •Localization Nuts and Bolts
- •.NET Resource Management Classes
- •Creating Text Resources
- •Using Visual Studio.NET for Internationalization
- •Image Resources
- •Using Image Lists
- •Programmatic Access to Resources
- •Reading and Writing RESX XML Files
- •The Basic Principles of GDI+
- •The Graphics Object
- •Graphics Coordinates
- •Drawing Lines and Simple Shapes
- •Using Gradient Pens and Brushes
- •Textured Pens and Brushes
- •Tidying up Your Lines with Endcaps
- •Curves and Paths
- •The GraphicsPath Object
- •Clipping with Paths and Regions
- •Transformations
- •Alpha Blending
- •Alpha Blending of Images
- •Other Color Space Manipulations
- •Using the Properties and Property Attributes
- •Demonstration Application: FormPaint.exe
- •Why Use Web Services?
- •Implementing Your First Web Service
- •Testing the Web Service
- •Implementing the Web Service Client
- •Understanding How Web Services Work
- •Summary
- •Workshop
- •How Do Web References Work?
- •What Is UDDI?
- •Summary
- •Workshop
- •Passing Parameters and Web Services
- •Accessing Data with Web Services
- •Summary
- •Workshop
- •Managing State in Web Services
- •Dealing with Slow Services
- •Workshop
- •Creating New Threads
- •Synchronization
- •Summary
- •The String Class
- •The StringBuilder Class
- •String Formatting
- •Regular Expressions
- •Summary
- •Discovering Program Information
- •Dynamically Activating Code
- •Reflection.Emit
- •Summary
- •Simple Debugging
- •Conditional Debugging
- •Runtime Tracing
- •Making Assertions
- •Summary
638
Extreme C#
PART IV
other of these methods, directive or compilation option, enables debugging, but they both are not required together. If neither of these, directive or compilation option, are present, the Debug class does not operate, and there would be no output.
LISTING 31.2 Compilation Instructions for Listing 31.1
csc /d:DEBUG PlainDebugDemo.cs
Conditional Debugging
A program’s capability to turn debugging on and off as needed is called conditional debugging. During development, output from debugging can clutter up normal output or force paths of execution that isn’t necessary on every run. The System.Diagnostics namespace has both attributes and switches to turn debugging on and off as necessary. Listing 31.3 shows how to use attributes to control conditional debugging.
LISTING 31.3 Debugging with Conditional Attributes: ConditionalDebugDemo.cs
#define DEBUG
using System;
using System.Diagnostics;
///<summary>
///Conditional Debug Demo.
///</summary>
class ConditionalDebugDemo
{
static bool Debugging = true;
[Conditional(“DEBUG”)]
static void SetupDebugListener()
{
TextWriterTraceListener myListener =
new TextWriterTraceListener(Console.Out);
Debug.Listeners.Add(myListener);
}
[Conditional(“DEBUG”)] static void CheckState()
{
Debug.WriteLineIf(Debugging, “Debug: Entered CheckState()”);
}
LISTING 31.3 continued
static void Main(string[] args)
{
SetupDebugListener();
CheckState();
}
}
Runtime Debugging
CHAPTER 31
639
31
UNTIMER
EBUGGINGD
And here’s the output:
Debug: Entered CheckState()
Two features of Listing 31.3 are of primary interest: the Conditional attribute and a Boolean condition on output. The Conditional attribute is placed at the beginning of a method that can be turned on and off at will. The condition causing the method to be invoked is either the #define DEBUG directive at the top of the listing or the command line /d:DEBUG option, shown in Listing 31.4. If neither of these, directive or command line option, is present, the methods with the Conditional attribute are invoked when called by the Main() method.
LISTING 31.4 Compilation Instructions for Listing 31.3
csc /d:DEBUG ConditionalDebugDemo.cs
The second item of interest in Listing 31.3 is the Boolean condition parameter of the
WriteLineIf() method in the CheckState() method. The WriteLineIf() method of the
Debug class has a first parameter that takes a bool. In the example, the static class field Debugging is used as an argument. It’s set to true, but had it been set to false, there would have been no output.
The examples presented so far expect that the code will be recompiled to turn debugging on and off. In a development environment, this is fine. However, in production, such luxury is not likely to be available. That’s why the example in Listing 31.5 uses the
BooleanSwitch and Trace classes.
LISTING 31.5 Implementing Debugging with a Boolean Switch:
BooleanSwitchDemo.cs
using System;
using System.Diagnostics;
///<summary>
///BooleanSwitch Demo.
640
Extreme C#
PART IV
LISTING 31.5 continued
/// </summary>
class BooleanSwitchDemo
{
BooleanSwitch traceOutput = new BooleanSwitch(“TraceOutput”, “Boolean Switch Demo”);
void SetupDebugListener()
{
TextWriterTraceListener myListener =
new TextWriterTraceListener(Console.Out);
Trace.Listeners.Add(myListener);
}
void CheckState()
{
Trace.WriteLineIf(traceOutput.Enabled,
“Debug: Entered CheckState()”);
}
static void Main(string[] args)
{
BooleanSwitchDemo bsd = new BooleanSwitchDemo();
bsd.SetupDebugListener();
bsd.CheckState();
}
}
And the output is:
Debug: Entered CheckState()
The CheckState() method of Listing 31.5 is similar to the same method in Listing 31.3, except that the WriteLineIf() method uses the Enabled property of a BooleanSwitch object as its first parameter. The BooleanSwitch class is instantiated with a first parameter as the display name and a second parameter as a description.
An entry must be added to the program’s configuration file to turn on tracing. Listing 31.6 shows how to add the BooleanSwitch display name entry into the configuration file. The configuration file must have the same name as the executable with a .config extension.
LISTING 31.6 BooleanSwitch entry in Configuration File: BooleanSwitchDemo.config
<configuration>
<system.diagnostics>
LISTING 31.6 continued
<switches>
<add name=”TraceOutput” value=”1” /> </switches>
</system.diagnostics>
</configuration>
LISTING 31.7 Compilation Instructions for Listing 31.5
csc /d:TRACE BooleanSwitchDemo.cs
Runtime Debugging
CHAPTER 31
641
31
UNTIMER
EBUGGINGD
Runtime Tracing
Runtime tracing is the capability to perform debug tracing while a program is running. Sometimes it’s necessary to have more control over what debugging information is displayed. Specific types of problems often indicate what information should be displayed in trace output. The TraceSwitch class is similar to the BooleanSwitch class in that it allows you to create a configuration file or set an environment variable. However, its real value comes in being able to specify a finer degree of granularity in determining what information is displayed. The example in Listing 31.8 demonstrates how to use the
TraceSwitch class.
LISTING 31.8 TraceSwitch Class Demo: TraceSwitchDemo.cs
using System;
using System.Diagnostics;
///<summary>
///TraceSwitch Demo.
///</summary>
class TraceSwitchDemo
{
public static TraceSwitch traceOutput = new TraceSwitch(“TraceOutput”, “TraceSwitch Demo”);
void SetupDebugListener()
{
TextWriterTraceListener myListener =
new TextWriterTraceListener(Console.Out);
Trace.Listeners.Add(myListener);
}
642
Extreme C#
PART IV
LISTING 31.8 continued
void CheckState()
{
Trace.WriteLineIf(traceOutput.TraceInfo,
“Trace: Entered CheckState()”);
}
static void Main(string[] args)
{
TraceSwitchDemo tsd = new TraceSwitchDemo();
tsd.SetupDebugListener();
tsd.CheckState();
}
}
And here’s the output:
Trace: Entered CheckState()
The implementation of the TraceSwitch is similar to the BooleanSwitch, except that the first parameter to the WriteLineIf() method in the CheckState() method is the TraceInfo property of the TraceSwitch class. This parameter can be any of the possible values corresponding to a member of the TraceLevel enum, shown in Table 31.1.
TABLE 31.1 TraceLevel Enum
TraceLevel enum |
Description |
Verbose |
Output everything |
Info |
Output info, error, and warning |
Warning |
Output error and warning |
Error |
Output error |
Off |
Output nothing |
|
|
TraceSwitch must be set in a configuration file. Values may be from 0 to 4 with Verbose equal to 4 and descending to Off, which is equal to 0. It’s possible to create a custom switch by inheriting the Switch class and defining Boolean properties with your own unique names that map to the available members of the TraceLevel enum. The configuration file in Listing 31.9 has TraceOutput set to 3, which causes evaluation of
TraceInfo to return true.