Export (0) Print
Expand All

Conditional Methods Tutorial

Visual Studio .NET 2003

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.

Sample Files

See Conditional Methods Sample to download and build the sample files discussed in this tutorial.

Further Reading

Tutorial

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:

  • Using #ifdef, define both debug and release versions of a macro. The debug version calls the tracing code, and the release version does nothing. Because C# doesn't support macros, this method doesn't work.
  • Have two implementations of the code being called. That is, in the debug version, have full functionality, and in the retail version, have empty stubs for the methods. Users then choose which one to include when linking the project. The problem with this approach is that the retail builds contain calls to empty methods, and the configuration is more complex.

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:

  • #define the preprocessing identifier in the source code directly. (See an example of this approach in Conditional.)
  • Define the preprocessing identifier on the C# command line via the /define option (/d). This approach is used in the following example.

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.

Example

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.

File #1: Creating Conditional Methods

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); 
       } 
   } 
}

Code Discussion

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 17.4.2 The Conditional attribute in the C# Language Specification for more information.

File #2: Using the Conditional Method

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"); 
   } 
}

Code Discussion

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.

Sample Run

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

See Also

C# Tutorials

Show:
© 2014 Microsoft