Commenting out Code in C# (Oldie but Goldie Tip)
I usually “comment out” code
- when something does not work as expected and I am looking for a workaround, or
- when I want to quickly try out an idea for an alternative solution
- I feel that using source control is too much hassle for what I’m trying to do in this situation.
The term “comment out” obviously comes from using code comments to hide source code from the compiler. C# has two kinds of comments that can be used for this, each with their pros and cons:
- End-of-line comments (“// this is a comment”) can be nested, i.e. you can comment a commented line. But they do not explicitly convey the start and the end of a commented section when looking at adjacent commented lines.
- Block comments (“/* this is a comment, possibly spanning several lines */”) do have an explicit start and end, but cannot be nested; you cannot surround a block comment with a block comment.
For disabling full lines of code, a different approach is to use the “#if … #endif” directive which tells the C# compiler to consider the code inside only if the specified symbol is defined. So to disable code, you simply specify a symbol that does not exist:
#if SOME_UNDEFINED_SYMBOL ...one or more lines... #endif
Using the preprocessor for this purpose is nothing new, especially to those with a C/C++ background. On the other hand, considering how often I watch developers use comments in situations where “#if” would have clear advantages, maybe this blog post benefits at least some people out there.
“#if” directives can be nested
The C# compiler does not blindly look for a closing “#endif”; it understands which “#endif” belongs to which “#if”, so e.g. the following is possible:
#if DISABLED ...some code... #if DEBUG ...debug code... #endif ...some code... #endif
You can express why you disabled a specific block of code
For example, you could use “#if TODO” when you are working on new code, but want to quickly run the program again without that code before continuing.
Something like “#if TO_BE_DELETED” (or maybe “#if DEL” for less typing) could mark code that you intend to remove after compiling the project and running the unit tests. If you are consistent with the naming of the symbol, performing a cleanup across the project is easy, because searching for “#if SYMBOL“ works well.
Obviously, you could choose more descriptive symbols (e.g. “#if TODO_DATA_ACCESS” and “#if TODO_CACHING") to differentiate different places of ongoing work. But if you think you need this, it could be a sign you are trying to juggle too many balls at once.
“#else” is great while you work on replacing code
Sometimes, when I have to deal with a non-obvious or even buggy third-party API, writing code involves a lot of experimentation. Then I like to keep old code around as a reference for a moment:
#if OLD_WORKAROUND ...old code... #else ...new code... #endif
You can easily toggle code on/off
You can enable the disabled code simply by defining the symbol, either using “#define” in the same source file or as a conditional compilation symbol for the whole project.
Alternatively, you can invert the condition for a specific “#if” with a “!” in front of the symbol:
#if !DISABLED ...some code... #endif
Being able to quickly switch code off and back on, or – in conjunction with “#else” – to switch between old and new code without losing the exact start and end positions of the code blocks is a huge plus. I use this e.g. when working on interactions in GUIs where I have to decide whether the old or the new code makes the user interface “feel” better.
Notes on disabled code
- Disabled code in a code base should always be viewed as a temporary measure, because code that never gets compiled “rots” over time. To the compiler/IDE, disabled code is plain text that is not affected by refactoring or renaming, i.e. at some point it is no longer valid.
- Try to get rid of disabled code as soon as possible, preferably before committing to source control.
- Last, but not least: Consider using source control for what it is good at - it exists for a reason. For instance, when experiments involve changes to many files, a new branch may be the better choice.