This article has been excerpted from book "The Complete Visual C# Programmer's Guide" from the Authors of C# Corner.

The C# preprocessor is a macro processor that the C# compiler automatically uses to transform your program before actual compilation. The C# preprocessor allows you to define macros, which are brief abbreviations for longer constructs.

A preprocessor directive must be the only instruction on a line. Preprocessing directives start with #, followed by an identifier that is the directive name. For example, #define is the directive. White space is allowed before and after the #.

The C# language's preprocessor directives are as follows:

  • #define
  • #if
  • #else
  • #elif
  • #endif
  • #undef
  • #warning
  • #error
  • #line
  • #region
  • #endregion

The main uses of directives include conditional compilation, line control, error and warning reporting, and region and end region. Let's take a preliminary look at each.

Conditional compilation: Using special preprocessing directives, you can include or exclude parts of the program according to various conditions.

Line control: If you use a program to combine or rearrange source files into an intermediate file that is then compiled, you can use line control to inform the compiler where each source line originated.

Error and warning reporting: The directive #error causes the preprocessor to report a fatal error. The directive #warning is much like the directive #error, but it causes the preprocessor to issue a warning and continue preprocessing.

Region and end region: These new directives, not found in C and C++, allow you to specify a block of code that you can expand or collapse.

Before further explaining the meaning of each preprocessor directive, it's helpful to see how to define these directives. Listings 5.59 and 5.60 illustrate the two methods for defining directives: in your C# program and on the command line at compile-time.

Listing 5.59: Define Example 1


#define
TEST

using
System;

public
class MyClass
{
    public static void Main()
    {

#if
(TEST)
        Console.WriteLine("TEST is defined");

#else

Console.WriteLine("TEST is not defined");
#endif
        Console.ReadLine();
    }
}


This first example of directive defining produces the output in Figure 5.17.

Figure5.17.gif

Figure 5.17: Screen Output Generated from Listing 5.59

Illustrating the second means of defining preprocessor directives is the code in Listing 5.60, which you compile using the /define:TEST compiler option.

Listing 5.60: Define Example 2


using
System;

public
class MyClass
{
    public static void Main()
    {

#if
(TEST)
Console.WriteLine("TEST is defined");

#else

        Console.WriteLine("TEST is not defined");

#endif
        Console.ReadLine();
    }
}


This code generates the output in Figure 5.18.

Figure5.18.gif

Figure 5.18: Screen Output Generated from Listing 5.60

#define Directive

The #define directive allows you to define a symbol that, when used as the expression passed to the #if directive, causes the expression to evaluate to true.

#undef Directive

The #undef directive allows you to undefine a symbol that, when used as the expression in an #if directive, causes the expression to evaluate to false.

For the #undef example in Listing 5.61, compile the code with the /D:DEBUG compiler option.

Listing 5.61: Undef Example


#undef
DEBUG

using
System;

public
class MyClass
{
    public static void Main()
    {

#if
DEBUG
Console.WriteLine("DEBUG is defined");

#else

        Console.WriteLine("DEBUG is not defined");

#endif

        Console.ReadLine();
    }
}


The code snippet produces the screen output shown in Figure 5.19.

Figure5.19.gif

Figure 5.19: Screen Output Generated from Listing 5.61

#if Directive

The #if directive allows you to conditionally choose to include code if the expression is true and in its simplest form consists of the following elements:


#if
expression
controlled text

#endif
/* expression */

The comment following the #endif is not required, but it is a good practice because it helps people match the #endif to the corresponding #if. Such comments should always be used, except in short conditionals that are not nested.

#else Directive

The #else directive can be added to a conditional directive to provide alternative text to be used if the condition is false. It consists of the following elements:


#if
expression
text-if-true

#else
/* Not expression */
text-if-false

#endif
/* Not expression */

If the expression is nonzero and thus the text-if-true element is active, then #else acts like a failing conditional and the text-if-false element is ignored.

#elif Directive

Like #else, the #elif directive goes in the middle of an #if-#endif pair and subdivides it. It does not require a matching #endif of its own. Like #if, the #elif directive includes an expression to be tested.

The text following the #elif is processed only if the original #if condition fails and the #elif condition succeeds. More than one #elif can go in the same #if-#endif group. In the case of multiple #elif directives, the text after each successive #elif is processed only if all previous #elif directives have failed. You may use the #else directive after any number of #elif directives, but an #elif directive may not follow #else. Listing 5.62 illustrates the use of the #if-#elif-#else preprocessor structure.

Listing 5.62:If-Elif-Endif Example


#define
DEBUG
#define
VC_V6

using
System;
public
class MyClass
{
    public static void Main()
    {

#if
(DEBUG && !VC_V6)
Console.WriteLine("DEBUG is defined");

#elif
(!DEBUG && VC_V6)
Console.WriteLine("VC_V6 is defined");

#elif
(DEBUG && VC_V6)
        Console.WriteLine("DEBUG and VC_V6 are defined");

#else

Console.WriteLine("DEBUG and VC_V6 are not defined");

#endif

        Console.ReadLine();
    }
}


Figure5.20.gif

Figure 5.20: Screen Output Generated from Listing 5.62

#endif Directive

The #endif directive specifies the end of a conditional directive that begins with the #if directive.

#error Directive

The directive #error causes the preprocessor to report a fatal error. The tokens forming the rest of the line following #error are used as the error message.

Listing 5.63:Error Example


#define
DEBUG

public
class MyClass
{
    public static void Main()
    {

#if
DEBUG
#error
DEBUG is defined
#endif

    }
}


#warning Directive

The directive #warning is much like the directive #error, but it causes the preprocessor to issue a warning and continue preprocessing. The tokens following #warning are used as the warning message. Listing 5.64 presents an example.

Listing 5.64: Warning Example

#define
DEBUG

public
class MyClass
{
    public static void Main()
    {
#if DEBUG
#warning
DEBUG is defined
#endif

    }
}


#line Directive

The #line directive (an example of which is shown in Listing 5.65) specifies the original line number and source file name for subsequent input in the current preprocessor input file.

Listing 5.65: Line.cs, Line Example


using
System;
public
class MyClass
{
    public static void Main()
    {

#line
100 "abc.sc" // change file name in the compiler output
        int i; // error will be reported on line 100, because of intt
        /* abc.sc(100,3): error CS0246: The type or namespace name 'intt' could not be

        found (are you missing a using directive or an assembly reference?) */

    }
}


#region and #endregion Directives

The #region directive allows you to specify a block of code that you can expand or collapse when using the outlining feature of the Visual Studio Code Editor. Listing 5.66 illustrates the use of #region, paired with the #endregion directive, which marks the end of the block.

Listing 5.66: Region EndRegion Example


#region
MyClass definition

public
class MyClass
{
    public static void Main()
    {
    }
}

#endregion


Conclusion


Hope this article would have helped you in understanding C# Preprocessor Directives. See other articles on the website on .NET and C#.

visual C-sharp.jpg The Complete Visual C# Programmer's Guide covers most of the major components that make up C# and the .net environment. The book is geared toward the intermediate programmer, but contains enough material to satisfy the advanced developer.

Next Recommended Readings