C# preprocessor is fundamentally very similar to C preprocessor and the whole concept in C# has been taken from C language specification.
"The C preprocessor is a macro processor that is used automatically by the C compiler to transform your program before actual compilation. It is called a macro processor because it allows you to define macros, which are brief abbreviations for longer constructs."
But in C# only concept has been taken from C. But the C# compiler does not have a separate preprocessor, the directives described in this C# are processed as if there was one. Unlike C and C++ directives, you cannot use these directives to create macros.
A preprocessor directive must be the only instruction on a line. Preprocessing directives are lines in your program that start with '#'. Whitespace is allowed before and after the '#'. The '#' is followed by an identifier that is the directive name. For example, '#define' is the directive
The C# language's preprocessor directives are as follows
- #if
- #else
- #elif
- #endif
- #define
- #undef
- #warning
- #error
- #line
- #region
- #endregion
Main use of directives are
- 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, which is then compiled, you can use line control to inform the compiler of where each source line originally came from.
- Error and Warning reporting: The directive '#error' causes the preprocessor to report a fatal error and the directive '#warning' is like the directive '#error', but causes the preprocessor to issue a warning and continue preprocessing.
Region and Unregion is new directives. It was not in C and C++ list of directives. I don't know the intention of C# developers to excludes number of directive from C and C++ list but they picked what people use atmost from list of C and C++ directive. Before telling meaning of each preprocessor directive I want to explain how to define preprocessor directive.There are two method to define directive.
- Define in your C# program.
- Define them at command line on compile time.
Here is an example for first way
Example
#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
}
}
Output
TEST is defined
In other way you can define it at command line. So program will be like this.
Example
using System;
public class MyClass
{
public static void Main()
{
#if (TEST)
Console.WriteLine("TEST is defined");
#else
Console.WriteLine("TEST is not defined");
#endif
}
}
At compile time user can define as below
csc /define:TEST MyClass.java
Output
TEST is defined
And if the command line will be like
csc MyClass.java
Output
TEST is not defined
Now its time to explain about various preprocessor define.
#if directive
The '#if' directive in its simplest form consists of
#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.
Above two example have shown how to use '#if' directive.
#else directive
The '#else' directive can be added to a conditional to provide alternative text to be used if the condition is false. This is what it looks like:
#if expression
text-if-true
#else /* Not expression */
text-if-false
#endif /* Not expression */
If expression is nonzero, and thus the text-if-true is active, then '#else' acts like a failing conditional and the text-if-false is ignored.
#elif directive
'#elif' stands for "else if". Like '#else', it goes in the middle of a '#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 failed and the '#elif' condition succeeds. More than one '#elif' can go in the same '#if'-'#endif' group. Then the text after each '#elif' is processed only if the '#elif' condition succeeds after the original '#if' and any previous '#elif' directives within it have failed. '#else' is equivalent to '#elif 1', and '#else' is allowed after any number of '#elif' directives, but '#elif' may not follow '#else'.
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
}
}
Output
DEBUG and VC_V6 are defined
#endif directive
#endif specifies the end of a conditional directive, which began with the #if directive.
#define directive
#define lets you define a symbol, such that, by using the symbol as the expression passed to the #if directive, the expression will evaluate to true
#undef directive
#undef lets you undefine a symbol, such that, by using the symbol as the expression in a #if directive, the expression will evaluate to false.
Example
// compile with /D:DEBUG
#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
}
}
Output
DEBUG is not defined
The '#error' and '#warning' Directives
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.
The directive '#warning' is like the directive '#error', but causes the preprocessor to issue a warning and continue preprocessing. The tokens following '#warning' are used as the warning message.
Example 1
#define DEBUG
public class MyClass
{
public static void Main()
{
#if DEBUG
#error DEBUG is defined
#endif
}
}
Example 2
#define DEBUG
public class MyClass
{
public static void Main()
{
#if DEBUG
#warning DEBUG is defined
#endif
}
}
#line Directive
#line is a directive that specifies the original line number and source file name for subsequent input in the current preprocessor input file.
Example
using System;
public class MyClass
{
public static void Main()
{
#line 100 "abc.sc" // change file name in the compiler output
intt i; // error will be reported on line 101
}
}
#region Directive
#region lets you specify a block of code that you can expand or collapse when using the outlining feature of the Visual Studio Code Editor.
Example
#region MyClass definition
public class MyClass
{
public static void Main()
{
}
}
#endregion
#endregion
#endregion marks the end of a #region block.