Several of people have written about this one, but it still gets used and I feel I should add my $0.02. (That’s Australian money, by the way, so it probably works out at not very much in your own currency.)
This post is specific to C#, as .NET has the ConditionalAttribute class which allows methods to be compiled and invoked only if there’s a particular compilation variable set.
Consider the code below:
private static void Hello()
{
Console.WriteLine("Hello, world!");
}
private static void Goodbye()
{
Console.WriteLine("Goodbye, cruel world!");
}
public static void GreetTheWorld()
{
#if DEBUG
Hello();
#endif
Goodbye();
}
Let’s say that we compile this in Debug mode with code analysis turned on and warnings set to errors. (We all compile with warnings == errors, don’t we?) All is well.
We go to run our unit tests again in Release mode prior to check-in, so we recompile in Release mode. (Or, if we’re lazy, we just check in from our Debug build and let our build server compile and run the tests in Release mode.)
Oops. CA1811 violation: you have uncalled private methods in your code. Please call them if you meant to call them, or remove them if not. The FxCop engine will never notice that our #if DEBUG directive has compiled out the call to our Hello() method, so code analysis throws an error.
Use this one instead:
[Conditional("DEBUG")]
private static void Hello()
{
Console.WriteLine("Hello, world!");
}
private static void Goodbye()
{
Console.WriteLine("Goodbye, cruel world!");
}
public static void GreetTheWorld()
{
Hello();
Goodbye();
}
This makes the code analysis tooling much happier.
Let’s consider the first piece of code again, though, and edit it in Release mode. Perhaps we’d like to rename our methods to something more descriptive of what they do: PrintHello() and PrintGoodbye(). So, we whip out our trusty refactoring tool (^R ^R in Visual Studio) and tell it to rename our methods.
Here’s what we end up with (remembering that we’re in Release mode):
private static void PrintHello()
{
Console.WriteLine("Hello, world!");
}
private static void PrintGoodbye()
{
Console.WriteLine("Goodbye, cruel world!");
}
public static void GreetTheWorld()
{
#if DEBUG
Hello();
#endif
PrintGoodbye();
}
Oops. We’ve introduced a compilation error because the refactor/rename operation uses the compiled version of the code to check for symbol usage, and our call to the former Hello() method doesn’t appear in the compiled assembly because the #if DEBUG
check caused it to not be compiled. We’ve left the old call to Hello() unchanged.
If we’d performed the same operation on the second piece of code instead, we’d be fine.