19.2 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 and 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", s); // Dump methodcall
}
}
Client code can simply call this method on method entry, as follows:
void DoWork( ) {
Logger.LogMethodCall( );
Console.WriteLine("Working...");
}
When client code is compiled with METHODCALL
defined, the C# compiler emits calls to the
LogMethodCall function. If
METHODCALL is not defined, the compiler omits the
calls entirely.
|