Using Preprocessor Directives in C#

Introduction

C# preprocessor directives are commands that are meant for the C# compiler. Using preprocessor directives you instruct the C# compiler to alter the compilation process in some way. For example you may instruct the C# compiler that a particular block of code be excluded from the compilation process. This article examines several C# preprocessor directives available, with an example of each.

#define and #undef

The #define preprocessor directive is used to define a symbol or a named token. You use this symbol later in your code with #if and #elif preprocessor directives. Consider the following line of code:

#define DEBUG

The above line of code defines a symbol – DEBUG. Although not mandatory, it is a common practice to define these symbols in upper case. You will find this line similar to a variable declaration but the difference is that it won’t reserve any memory as such and can’t hold any value. One important thing to remember is that all the #define directives you are using must appear at the top of the source code file. If you place them somewhere within the code you will get an error like this:

#define directives must appear at the top of the source code file or you'll get an error
#define directives must appear at the top of the source code file or you’ll get an error

A symbol can be defined using #define or can also be passed via command line. The symbol thus defined can be undefined using #undef directive.

#undef DEBUG

Un-defining a symbol is like erasing it so that it doesn’t exist for the later code.

#if, #else, #elif and #endif

The real use of symbols defined using #define is when they are coupled with #if and #elif directives. These preprocessor directives allow you to test whether a particular symbol has been defined. Based on the outcome of this test you can conditionally compile a piece of code. The following code shows how this is done.

#define DEBUG
...
#if DEBUG
    Console.WriteLine("You have defined DEBUG symbol");
#endif

In the above piece of code you first defined the DEBUG symbol. Somewhere later in your code you used #if directive to check whether DEBUG is defined. If so you output a message using Console.WriteLine(). If you run this application you will get an output as shown below:

You have defined DEBUG symbol
You have defined DEBUG symbol

If you remove the #define line or un-define the DEBUG symbol and then run the application, you won’t see the message because the #if condition will evaluate to false.

You can test for multiple symbols using #elif as shown below:

#if STANDARD
    Console.WriteLine("You have defined STANDARD symbol");
#elif PROFESSIONAL
    Console.WriteLine("You have defined PROFESSIONAL symbol");
#elif ULTIMATE
    Console.WriteLine("You have defined ULTIMATE symbol");
#endif

You can also test multiple symbols in one #if using operators – ==, !=, && and ||. The following example shows how:

#if STANDARD && EVAL
    Console.WriteLine("You have defined STANDARD and EVAL symbols");
#endif

#warning and #error

As you might have already guessed the #warning and #error preprocessor directives are used to emit warning and error messages respectively. The difference between #warning and #error is that #warning displays the warning message but doesn’t halt the compilation process. However, #error halts the compilation in addition to displaying the error message. The following code shows how they are used:

#if EVAL && FULL
    #warning "You have defined EVAL as well as FULL"
#endif

The above code checks if symbol EVAL as well as FULL is defined, and if so a warning message is outputted. If you build the project and both of these symbols are defined you should get a warning as shown below:

You have defined EVAL as well as FULL warning
You have defined EVAL as well as FULL warning

If you would have used #error instead of #warning you would have got an error as shown below:

You have defined EVAL as well as FULL error
You have defined EVAL as well as FULL error

#region and #endregion

The #region and #endregion preprocessor directives come in handy when you are coding inside Visual Studio IDE. They allow you to define a region of code as one single block so that the entire block can be collapsed or expanded. Consider the following piece of code:

define a region of code as one single block
define a region of code as one single block

Here, you define a region, Public Properties, using the #region and #endregion directives. This region contains all the public properties defined by a class. The region can be expanded or collapsed using the – or + icon shown in the margin of the Visual Studio editor. If you are writing hundreds of lines of code in a single file then using #region and #endregion to divide the entire code into multiple logical regions can enhance your coding experience.

#line

The #line preprocessor director is used to modify the line number and file name that appears in the compiler error messages. Consider, for example, the following code:

namespace CSPreProcessorDirectivesDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            inta a = 100;
            Console.ReadLine();
        }
    }
}

There is a syntax error at line no. 14 (inta a = 100) and the file name is Program.cs. If you try to compile this project you will get the following error.

Program.cs error
Program.cs error

Now, you can use #line directive to change the default line number and file name :

 #line 400 "MyFile.cs"
inta a = 100;

Here, the line number is set to 400 and file name is set to MyFile.cs. Compiling this code gives an error as shown below:

MyFile.cs error
MyFile.cs error

As you can see the line no. and file name displayed in the Error List is now picked from the #line directive. The #line directive is more useful in situations where source code is modified by some external tools or systems (ASP.NET is one such example).

#pragma

#pragma preprocessor directive instructs the compiler about the compilation of the file under consideration. The instructions you used with #pragma must be supported by the compiler. As far as the C# compiler is concerned the following two instructions are supported:

#pragma warning
#pragma checksum

Just as an example of using #pragma, consider the following line of code where warning 219 has been disabled:

#pragma warning disable 219

The warning number 219 is for “The variable is assigned but its value is never used”. Once disabled the compiler will stop reporting the 219 warnings.

Summary

C# Preprocessor Directives are commands that are meant for the C# compiler. This article illustrated the use of #define, #undef, #if, #else, #elif, #endif, #warning, #error, #region, #endregion, #line and #pragma preprocessor directives.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read