Improving Conditional Compilation
One reason people start to introduce conditional compilation for their projects is to enable certain logging/tracing features for debug builds only and silently exclude them from release builds. The most common mechanism to enable conditional compilation is using a combination of environment variables and a preprocessor. If possible, conditional compilation should be avoided because it creates additional complexity and is a common source for errors. Errors introduced by conditional compilation are not only limited to getting your project to compile correctly under all configurations. Especially when using the preprocessor to enable conditional compilation you might easily forget to wrap a section of code with the appropriate guard clause, in the context of logging this may bring you into a situation where you accidentally log sensitive information in a release build.
There are certain ways you can mitigate this risk. One of them is to use a custom post build procedure to scan your compiled products for log calls that should be nonexistent in release builds. If you’re building a .NET product this can be done using reflection over your assemblies, but there’s a better approach you can use in .NET.
The ConditionalAttribute is an attribute applied to a method that instructs the compiler to omit all calls to this method when a symbol specified in the Attribute is not present during compilation. For example, we can have a ConditionalAttribute [Conditional(“DEBUG”)] applied to a method. If the symbol DEBUG is defined at compile time, all calls to this method will be compiled as usual. If the symbol is not present, all calls to this method will be removed.
This results in a safer approach to conditional compilation because consumers of such a method are relieved from the responsibility to remove their calls when a certain condition is not met. The Debug and Trace classes make use of this feature to provide transparent conditional debug/trace output respectively.
Of course there are is a host of other applications for using ConditionalAttribute than only removing calls to logging frameworks. There’s one caveat though, the method marked with the ConditionalAttribute itself will not get stripped from the resulting assembly (see Debug/Trace classes respectively). So if you use ConditionalAttribute as a safer alternative to preprocessor guards, you might need to fall back on those guards once to remove the method. This way you can easily strip certain behavior from your application without leaving traces.
Complete stripping but the type remains