This tutorial demonstrates conditional methods, which provide a powerful mechanism by which calls to methods can be included or omitted depending on whether a preprocessor symbol is defined.
See
Conditional methods allow developers to create methods whose calls can be placed in the code and then either included or omitted during compilation based on a preprocessing symbol.
Suppose that you want to enable some assertion code in the debug builds and disable it in the retail builds. In C++, there is more than one way to have this functionality in your code, for example:
C# conditional methods provide a simple solution to this problem that is similar to the first approach listed above. There are two basic mechanisms to do this:
Conditional methods are used in the .NET Framework. The System.Diagnostics namespace contains a number of classes that support tracing and debugging in applications. Use the System.Diagnostics.Trace and System.Diagnostics.Debug classes to add sophisticated tracing and debugging to your application (functionality that can be compiled out of your retail builds through the use of conditional methods).
The example below shows how to implement a very simple tracing mechanism using conditional methods. System.Diagnostics.Trace provides much more sophisticated tracing mechanisms, but it uses the fundamental mechanism below to provide this functionality.
This example consists of two source files: the first file is the library that provides a tracing mechanism, and the second file is the client program that uses this library.
The code below shows a simple library that provides a tracing mechanism that displays trace messages to the system console. Clients can embed trace calls in the code and then be able to control whether the tracing gets called by defining symbols in their own compilation phase.
// CondMethod.cs
// compile with: /target:library /d:DEBUG
using System;
using System.Diagnostics;
namespace TraceFunctions
{
public class Trace
{
[Conditional("DEBUG")]
public static void Message(string traceMessage)
{
Console.WriteLine("[TRACE] - " + traceMessage);
}
}
}
The following line:
[Conditional("DEBUG")]
marks the Message method as being conditional (via the Conditional attribute). The Conditional attribute takes one parameter the preprocessing identifier that controls whether the method call is included when clients are compiled. If the preprocessing identifier is defined, the method is called; otherwise, the call is never inserted in the client's code.
There are restrictions on which methods can be marked as conditional; see
The following client program uses the Trace class defined in file #1 to do some simple tracing.
// TraceTest.cs
// compile with: /reference:CondMethod.dll
// arguments: A B C
using System;
using TraceFunctions;
public class TraceClient
{
public static void Main(string[] args)
{
Trace.Message("Main Starting");
if (args.Length == 0)
{
Console.WriteLine("No arguments have been passed");
}
else
{
for( int i=0; i < args.Length; i++)
{
Console.WriteLine("Arg[{0}] is [{1}]",i,args[i]);
}
}
Trace.Message("Main Ending");
}
}
Conditional code is included in client code depending on whether the preprocessing identifier is defined when the client code gets compiled.
Compiling with client code with the /d:DEBUG flag means that the compiler inserts the call to the Trace method. If the symbol is not defined, the call is never made.
The command:
tracetest A B C
gives the following output:
[TRACE] - Main Starting Arg[0] is [A] Arg[1] is [B] Arg[2] is [C] [TRACE] - Main Ending
The command:
tracetest
gives the following output:
[TRACE] - Main Starting No arguments have been passed [TRACE] - Main Ending