C# Preprocessor Directives allow dynamic code changes during compilation based on defined symbols. For an in-depth understanding of C# Preprocessor Directives, follow along with Mytour's informative article below.
Understanding C# Preprocessor Directives
1. Exploring Preprocessor Directives in C#.
2. Using Preprocessor Directives in C#.
3. Various Preprocessor Directives in C#.
1. Preprocessor Directives in C#
Preprocessor Directives are special commands inserted into code and analyzed by the compiler during project build. We utilize preprocessor directives to modify compiled code by adding or removing sections based on defined symbols.
All preprocessor directives start with #, and in a line, only whitespace characters appear before a preprocessor directive. Preprocessor directives are not statements, so they don't end with a semicolon (;).
The C# compiler does not have a separate preprocessor, but it handles directives individually. In C#, preprocessor directives are used to support conditional compilation. Unlike in C and C++, they are not used to create macros. A preprocessor directive must be unique on a line.
C# includes the following preprocessor directives:
#if
#else
#elif
#endif
#define
#undef
#warning
#error
#line
#region
#endregion
2. Using Preprocessor Directives in C#
We use preprocessor directives in C# to:
Conditional Compilation: By using special preprocessor directives, you can add or remove parts of the program under different conditions.
Line Control: If you are combining or arranging files into an intermediate file before compilation, you can use Line Control to inform the compiler about the location of the source lines.
Error Reporting and Warnings: The '#error' directive makes the preprocessor report a serious error, while the '#warning' directive makes the preprocessor issue a warning and continues preprocessing.
3. Preprocessor Directives in C#
#define and #undef
The #define preprocessor directive is used to define a symbol or macro token. You can use this token in your code with the #if and #elif preprocessor directives.
For a clearer illustration, refer to the following code snippet:
#define DEBUG
The code line above defines a symbol named DEBUG. While not mandatory, it's customary to define symbols in uppercase letters.
Essentially, the line is similar to declaring a variable, except it doesn't occupy any memory storage and cannot store any values.
An important note is that all #define directives you use must be placed at the beginning of the source code file. If placed elsewhere, it will result in an error message like the one below:
A symbol can be defined using #define or can also be passed through the command line. Therefore, a symbol may not be defined using the #undef directive.
#undef DEBUG
Undef is a symbol akin to deletion, making it non-existent for the code thereafter.
#if, #else, #elif, and #endif
Utilize symbols defined with #define when combined with #if and #elif directives. These preprocessor directives allow you to check whether a specific symbol has been defined or not. Based on the result of this check, you can conditionally compile code.
The example below illustrates how the code is compiled:
#define DEBUG
...
#if DEBUG
Console.WriteLine('You have defined DEBUG symbol');
#endif
In the code snippet above, we first define the DEBUG symbol. Next, we use the #if directive to check whether DEBUG is defined or not.
If it is, the output will display a message using Console.WriteLine(). When running this application, the output will appear as shown below:
If you delete the #define line or do not define the DEBUG symbol, then run the application, you won't receive the message because the #if condition will evaluate as false.
Additionally, you can check multiple symbols using #elif as shown below:
Alternatively, you can check multiple symbols within an #if preprocessor directive using operators - ==, !=, &&, and ||.
The example below illustrates how to use these operators:
#warning and #error
True to its name, the #warning and #error preprocessor directives are used to display corresponding warnings and errors. The sole difference between #warning and #error is that #warning continues to display messages during compilation, while #error temporarily halts the compilation process to show an error message.
The code snippet below illustrates the usage of #warning and #error:
#if EVAL && FULL
#warning 'You have defined EVAL as well as FULL'
#endif
The code snippet above checks whether the EVAL symbol as well as the FULL symbol is defined, and if so, a warning or message will be outputted. If you are building a project with both of these symbols defined, you will receive a warning like the one below:
If you use #error instead of #warning, you will encounter an error like the one below:
#region and #endregion
The #region and #endregion preprocessor directives are useful when coding in the Visual Studio IDE, allowing you to define a code region as a single block to collapse or expand the entire block. Refer to the example code snippet below:
Here, we define the Public Properties region using the #region and #endregion directives. This region contains all the public properties defined by a class. You can expand or collapse the region using the - or + icons in the Visual Studio editor margin.
When dealing with hundreds of different lines of code in a file, using the #region and #endregion preprocessor directives to divide the entire code into logical regions enhances your coding experience.
#line
The #line preprocessor directive is used to modify the line number and file name appearing in compiler error messages. Consider the example below:
There is a syntax error on line 14 (inta a = 100), and the file name is Program.cs. If you attempt to compile this project, you will receive the following error message:
Now, you can use the #line directive to change the default line number and file name:
Here, the line number is set to 400, and the file name is set to MyFile.cs. When compiling this code snippet, it will return an error message like the one below:
As you can observe, line number 0 and the file name are displayed in the error list currently selected from the #line directive.
The #line preprocessor directive is valuable in cases where the source code is modified by external tools or systems (ASP.NET being an example).
#pragma
The #pragma preprocessor directive instructs the compiler on how to compile files under consideration. Directives using #pragma must be supported by the compiler. The C# compiler supports the following 2 directives:
#pragma warning
#pragma checksum
Here is an illustrative example of using #pragma, where warning 219 is disabled:
#pragma disable warning 219
Warning 219 is a warning for a variable being assigned but its value not being used. After disabling, the compiler will cease to display warning 219.
So, in this article, Mytour has just introduced you to the preprocessor directives in C#, along with illustrative examples for each directive. Additionally, readers can explore other articles on Mytour to delve deeper into operator overloading in C#.