Preprocessor Directives guide the compiler to preprocess information before the actual compilation begins.
Through these directives, you can control how the compiler compiles a file or which parts to compile. Common preprocessor directives include conditional compilation, macro definitions, etc.
All preprocessor directives start with a # and are on a single line. Only whitespace characters can appear before a preprocessor directive.
Preprocessor directives are not statements, so they do not end with a semicolon (;).
The C# compiler does not have a separate preprocessor, but the directives are processed as if there were one. In C#, preprocessor directives are used for conditional compilation. Unlike C and C++, they are not used to create macros. A preprocessor directive must be the only directive on its line.
The following table lists the preprocessor directives available in C#:
| Directive | Description |
|---|---|
#define |
Defines a symbol that can be used for conditional compilation. |
#undef |
Undefines a symbol. |
#if |
Begins a conditional compilation block, including the code block if the symbol is defined. |
#elif |
Includes the code block if the preceding #if or #elif condition is not met and the current condition is met. |
#else |
Includes the code block if the preceding #if or #elif condition is not met. |
#endif |
Ends a conditional compilation block. |
#warning |
Generates a compiler warning message. |
#error |
Generates a compiler error message. |
#region |
Marks a block of code that can be collapsed and expanded in an IDE, aiding in code organization and readability. |
#endregion |
Ends a code region. |
#line |
Changes the line number and file name in the compiler output, useful for debugging or code generation tools. |
#pragma |
Used to send special instructions to the compiler, such as disabling or restoring specific warnings. |
#nullable |
Controls the nullable context and annotations, allowing the enabling or disabling of compiler checks for nullable reference types. |
Example
#define DEBUG
#if DEBUG
Console.WriteLine("Debug mode");
#elif RELEASE
Console.WriteLine("Release mode");
#else
Console.WriteLine("Other mode");
#endif
#warning This is a warning message
#error This is an error message
#region MyRegion
// Your code here
#endregion
#line 100 "MyFile.cs"
// The next line will be reported as line 100 in MyFile.cs
Console.WriteLine("This is line 100");
#line default
// Line numbering returns to normal
#pragma warning disable 414
private int unusedVariable;
#pragma warning restore 414
#nullable enable
string? nullableString = null;
#nullable disable
#define is used to define a symbol (typically for conditional compilation), and #undef is used to undefine a symbol.
#define DEBUG#undef RELEASE
#define allows you to define a symbol so that, by using the symbol as an expression passed to the #if directive, the expression will return true. Its syntax is as follows:
#define symbol
The following program illustrates this:
Example
#define PI
using System;
namespace PreprocessorDAppl
{
class Program
{
static void Main(string[] args)
{
#if (PI)
Console.WriteLine("PI is defined");
#else
Console.WriteLine("PI is not defined");
#endif
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
PI is defined
You can use the #if directive to create a conditional directive.
Conditional directives are used to test whether a symbol is true. If it is true, the compiler executes the code between #if and the next directive.
The syntax for conditional directives is:
#if symbol ...
Where symbol is the name of the symbol to test. You can also use true and false, or place a negation operator before the symbol.
Common operators include:
==(equality)!=(inequality)&&(logical AND)||(logical OR)
You can also group symbols and operators with parentheses. Conditional directives are used to compile code for debug builds or when a specific configuration is specified. A conditional directive starting with a #if directive must be explicitly terminated with a #endif directive.
#define DEBUG#if DEBUG Console.WriteLine("Debug mode");#elif RELEASE Console.WriteLine("Release mode");#else Console.WriteLine("Other mode");#endif
The following program demonstrates the use of conditional directives:
Example
#define DEBUG
#define VC_V10
using System;
public class TestClass
{
public static void Main()
{
#if (DEBUG && !VC_V10)
Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && VC_V10)
Console.WriteLine("VC_V10 is defined");
#elif (DEBUG && VC_V10)
Console.WriteLine("DEBUG and VC_V10 are defined");
#else
Console.WriteLine("DEBUG and VC_V10 are not defined");
#endif
Console.ReadKey();
}
}
When the above code is compiled and executed, it produces the following result:
DEBUG and VC_V10 are defined
#warning is used to generate a compiler warning, and #error is used to generate a compiler error.
#warning This is a warning message#error This is an error message
Used for code folding to make code more readable.
#region MyRegion// Your code here#endregion
Used to change the line number and file name in the compiler output.
#line 100 "MyFile.cs"// The next line will be reported as line 100 in MyFile.cs Console.WriteLine("This is line 100");#line default// Line numbering returns to normal
Used to send special instructions to the compiler. The most common use is to disable specific warnings.
#pragma warning disable 414private int unusedVariable;#pragma warning restore 414
- Improve Code Readability: Using
#regioncan help separate code blocks and improve code organization. - Conditional Compilation: Through directives like
#if, different code can be compiled for development and production environments, facilitating debugging and release. - Warnings and Errors: Through
#warningand#error, developers can be alerted to specific issues during compilation.
By correctly using these preprocessor directives, you can better control the code compilation process, improving code flexibility and maintainability.
YouTip