In the examples you’ve seen so far, you’ve compiled your entire program whenever you compiled any of it. At times, however, you might want to compile only parts of your program depending on, for example, whether you are debugging or building your production code.
Before your code is compiled, another program called the preprocessor
runs and prepares your program for the compiler. The preprocessor
examines your code for special preprocessor directives, all of which
begin with the
pound sign (#
).
These directives allow you to define identifiers and then test for
their existence.
#define DEBUG
defines a preprocessor identifier, DEBUG
. Although
other preprocessor directives can come anywhere in your code,
identifiers must be defined before any other code,
including
using
statements.
You can test whether DEBUG
has been defined with
the #if
statement. Thus, you
can write:
#define DEBUG //... some normal code - not affected by preprocessor #if DEBUG // code to include if debugging #else // code to include if not debugging #endif //... some normal code - not affected by preprocessor
When the preprocessor runs, it sees the
#define
statement
and records the identifier DEBUG
. The preprocessor
skips over your normal C# code and then finds the #if - #else - #endif
block.
The #if
statement tests for the identifier
DEBUG
, which does exist, and so the code
between #if
and #else
is
compiled into your program, but the code between
#else
and #endif
is
not compiled. That code does not appear in your
assembly at all; it is as if it were left out of your source code.
Had the #if
statement failed—that is, if you
had tested for an identifier which did not exist—the code
between #if
and #else
would not
be compiled, but the code between #else
and
#endif
would be compiled.
You undefine an
identifier
with #undef
. The preprocessor works its way
through the code from top to bottom, so the identifier is defined
from the #define
statement until the
#undef
statement, or until the program ends. Thus
if you write:
#define DEBUG #if DEBUG // this code will be compiled #endif #undef DEBUG #if DEBUG // this code will not be compiled #endif
the first #if
will succeed
(DEBUG
is defined), but the second will fail
(DEBUG
has been undefined).
There is no switch
statement for the preprocessor,
but the #elif
and #else
directives provide great flexibility. The #elif
directive allows the else-if logic of “if DEBUG then action
one, else if TEST then action two, else action three”:
#if DEBUG // compile this code if debug is defined #elif TEST // compile this code if debug is not defined // but TEST is defined #else // compile this code if neither DEBUG nor TEST // is defined #endif
In this example the preprocessor first tests to see if the identifier
DEBUG
is defined. If it is, the code between
#if
and #elif
will be compiled,
and none of the rest of the code until #endif
,
will be compiled.
If (and only if) DEBUG
is not defined, the
preprocessor next checks to see if TEST
is
defined. Note that the preprocessor will not check for
TEST
unless DEBUG
is not
defined. If TEST
is defined, the code between the
#elif
and the #else
directives
will be compiled. If it turns out that neither
DEBUG
nor TEST
is defined, the
code between the #else
and the
#endif
statements will be compiled.
The
#region
preprocessor directive marks an area of text with a comment. The
principal use of this preprocessor directive is to allow tools such
as Visual Studio .NET to mark off areas of code and collapse them in
the editor with only the region’s comment showing.
For example, when you create a Windows application (covered in Chapter 13) Visual Studio .NET creates a region for code generated by the designer. When the region is expanded it looks like Figure 3-1. (Note: I’ve added the rectangle and highlighting to make it easier to find the region.)
You can see the region marked by the #region
and
#end region
preprocessor directives. When the
region is collapsed, however, all you see is the region comment
(Windows Form Designer generated code
), as
shown in Figure 3-2.
3.146.37.250