C# Preprocessor Directives
If you have ever worked with an application that bounces from your workstation, to QA, then to production the odds are high you have dealt with C# preprocessor directives. While C# does not have a preprocessing engine, these directives are treated as such. They have been named as such to be consistent with C and C++ for familiarity. Directives can be used to build classes based on the environment they will be deployed in, to grouping chunks of your source code together for collapsing inside the Visual Studio code editor. This article will go over each C# preprocessor directive.
C# has the following directives, all of which will be covered in this article:
- #if
- #else
- #elif
- #endif
- #define
- #undef
- #warning
- #error
- #line
- #region
- #endregion
Let’s start with #define and #undef. These directives are used to define and undefine symbols that evaluate to true (if using #define) when used in other logical directives. As you could imagine, #undef will undefine a given symbol (such that it yields false).
1 2 3 4 | |
With those two directives down, we can move on to #if, #else, #elif, and #endif directives. These directives let you step into or over chunks of code depending on the condition that is checked. As you can imagine, they behave like if, else if, and else statements in C#. The #endif directive must be used to finish off any statement or statements starting with the #if directive. You may use the ==, !=, &&, || operators to check various conditions. You can also group symbols and operators by using parentheses.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
In just these two examples I have already covered 6 of the 11 possible C# preprocessor directives. The next few will help you add messages to your compiler output.
Now let’s cover the #warning and #error directives. Both of these directives will throw Warnings or Errors respectively when you compile your application in Visual Studio. For example, you may want to throw a warning that you left debug mode on so you don’t accidentally deploy your application to production while it is running in a debug state:
1 2 3 4 5 6 7 8 9 10 11 12 | |
…and of course #error will cause an error to be displayed in the compiler output:
1 2 3 4 5 6 7 8 9 10 11 12 | |
The #line directive is more strange than the other preprocessor directives. Specifically, #line allows you to modify the compiler’s line number and optionally change the file name that is used for warning and error outputs. The syntax is as follows:
1 | |
Hidden will remove successive lines from the debugger until another #line directive is hit. Usually the #line directive is used in automated build process or code creators. But for an example if I use this chunk of code:
1 2 3 4 5 6 7 8 9 10 11 12 | |
Will produce this error output inside Visual Studio:
1 2 | |
Finally, we have the #region and #endregion. Every #region block must end with a #endregion block. When you define a block it allows you to expand and collapse code inside Visual Studio for easier reading and reference. There are some important points to note though: A #region block cannot overlap an #if block and vice versa . You can nest an #if block inside a #region block or a #region block inside an #if block though. So for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
I can expand and collapse the section inside Visual Studio as pictured:
…and that is all the possible C# preprocessor directives you can use! I love the #region one, since it allows you to lump your code together for easier reading.
