Conditional Compilation
The presence or absence of the DEBUG and TRACE symbols
tell the compiler how to handle calls to methods in the Debug and Trace classes.
If the DEBUG or TRACE symbols are not
defined, many of the method calls into the Debug and Trace classes
are optimized away completely. This can be a desirable feature for your own
types, and there are a number of ways to accomplish this with the .NET Framework
and the C# language.
One option is to bracket the calls with #if/#endif preprocessor
directives, as follows:
void DoWork() {
#if METHODCALL
Debug.WriteLine("MethodCall", "Entering MyClass::DoWork");
#endif
Console.WriteLine("Working...");
}Compiling this function with /d:METHODCALL, DEBUG
results in a call to Debug.WriteLine and a log of the method
entry. The downside to this approach is using preprocessor directives
such as this is arduous, error-prone, and the code quickly becomes unreadable.
An alternative is to use the ConditionalAttribute custom
attribute. When placed on a method, this attribute instructs the C# compiler
to conditionally omit calls to the method.
Using this approach we can define a reflection-driven logger, as follows:
public class Logger { [Conditional("METHODCALL")] public static void LogMethodCall() { StackFrame sf = new StackFrame(1); // Get preceding stack frame MethodBase mb = sf.GetMethod(); // Get refl. info for method Type t = mb.DeclaringType; // Get refl. info for type string s = String.Format("Entering {0}::{1}", t.Name, mb.Name); Debug.WriteLine("MethodCall", ...