We can use conditional directives in C# that will be executed at the pre-compiler to allow us determine which code will be compiled or not: #if and #endif.
To sue them, we need to define a symbol. What do you mean with a symbol? A symbol is like a variable that we will use for this purpose. You can declare one of those using #define or #undef and use it later to add some pre-compiler conditional directives. Let’s see an example:
#define DEVELOPMENT_MODE #undef PRODUCTION_MODE public class OleDB { public static OleDbDataReader ExecuteReader(string cmdText){ #if PRODUCTION_MODE srcDB = "c:\\server\\databases\\bd1.mdb"; #else srcDB = "c:\\bd1.mdb"; #endif } }
As a mere example, see how we could use a pre-compiler directive to set the database source when we are in production mode and when we are in development mode (since it could be in different folders), so it will be changed only changing which symbols are on and which are off.
You can use #define to set a symbol on, and #undef to set it off. The last you set will work:
#define MySymbol // MySymbol is now On #undef MySymbol // MySymbol is now Off #define MySymbol // MySymbol is On again
You can make more complex conditions and use more bifurcations with #if, #elif, #else and finally #endif. Like in this example:
#define DEVELOPMENT_MODE #undef PRODUCTION_MODE public class OleDB { public static OleDbDataReader ExecuteReader(string cmdText){ #if DEVELOPMENT_MODE && !PRODUCTION_MODE srcDB = "c:\\bd1.mdb"; #elif !DEVELOPMENT_MODE && PRODUCTION_MODE srcDB = "c:\\server\\databases\\bd1.mdb"; #else srcDB = ""; throw new Exception("No Enviroment Mode set"); #endif } }
You may have noticed looking at that example that an error may occur if we set both symbols (production and development) On or Off.
What can we do to avoid compiling with a symbols mistake?
We have more directives to help with that: #warning and #error. With #warning you can write something in the compiling messages to alert the developer of something. With #error you can directly stop compilation until the developer fixes the mistake.
#define DEVELOPMENT_MODE #undef PRODUCTION_MODE public class OleDB { public void someMethod(){ #if DEVELOPMENT_MODE && !PRODUCTION_MODE #warning DEVELOPMENT_MODE is ON #elif !DEVELOPMENT_MODE && PRODUCTION_MODE #warning PRODUCTION_MODE is ON #else #error There is no symbol defined or both production and development are. #endif } }
You can use this also to Trace your project, if you use the Trace options you know that despite it will only work when traces are active each trace condition asking if traces are active is consuming resources.
Using the precompiler conditions you can make traces to work only when a directive is set (for example: TRACE_MODE) and they will not run and consume any resources at all when the directive is off.
Using C#.Net default directives
To make it even easier Visual Studio already adds some directives so you don’t need to worry about declaring them on “Application_Start” or similar (and maybe forgetting when releasing!). The idea is that those directives will be changed when you compile for production most probably using a Source Control tool. So you can make use of these at any point:
#if DEBUG ... #elif RELEASE ... #endif #if TEST // When executing unit tests #endif #if !TEST // ... #endif