I don't know if the original designers had this line of thinking in mind originally, but this is how it makes sense to me.
Because you can only declare the method as type void AND it cannot be overridden AND it cannot be referenced as part of an interface, the compiler can simply ignore the method because it will have no dependencies if the specified mode doesn't match. If another method calls it in a non-matching mode, the compiler can simply treat it an invalid method call as if the attribute wasn't there.
John's example will work, but I would do something like this:
#if DEBUG
public static string TestStringForDebugOnly(...)
{
...
}
#endif
// Arguments are only for illustration.
public string CallingMethod(int id, string temp)
{
#if DEBUG
string result = TestStringForDebugOnly(id, temp);
#else
string result = TestString(id, temp);
#endif
return result;
}
I would expend the additional effort to wrap up all the DEBUG-related code (including the individual method calls) in preprocessor directives for two reasons. First, it provides its own built-in documentation; you know exactly what is supposed to run when, where and why. Second, if the code needs to be modified or removed, the amount of searching that needs to be done is greatly reduced, along with the need to repeatedly compile and re-compile to see what breaks.