Recipe 6.5 Conditionally Compiling Blocks of Code
Problem
Specific blocks of code
will be used only in a nonrelease build of your application. These
blocks of code should not be compiled into the release version of the
application. You need a way to conditionally compile specific blocks
of code based on the type of build.
Solution
There are two methods of
allowing or preventing code from being compiled. The first is to use
the C# preprocessor directives. The available preprocessor directives
are:
#define
#undef
#if
#elif
#else
#endif
The #define and
#undef preprocessor directives define and undefine
symbols. These symbols are then used by the #if
and #elif preprocessor directives to determine
whether the blocks of code they wrap are to be compiled.
The second method of allowing or preventing code from being compiled
is to use the
ConditionalAttribute
attribute to allow a method to be compiled based on a defined symbol.
This attribute is used to specify a method as conditionally compiled
as follows:
#define TRACE
...
[ConditionalAttribute("TRACE")]
public void TraceHelp(string message)
{
...
}
The TraceHelp method is compiled only when the
TRACE preprocessing identifier is defined.
Discussion
The ConditionalAttribute attribute can be used
only on methods to prevent them from being compiled and called at
runtime when the preprocessor identifier passed to the
ConditionalAttribute attribute's
constructor is undefined. Properties, indexers, and other members
cannot have this attribute.
Another limitation of this attribute is that it can be placed only on
a method that returns void. This makes sense,
since code that invokes this method doesn't expect a
return value, and will run successfully whether the method is
invoked. For example, in the code:
int retValue = Car.GetModelNumber( );
if the GetModelNumber method is not compiled, then
this code will not be able to function correctly.
Along these same lines, a method marked as
override cannot be marked with the
ConditionalAttribute attribute. However, the
virtual method that a method overrides may be marked with the
ConditionalAttribute attribute. If the virtual
method is marked with this attribute, all methods overriding it are
compiled and called based on whether the virtual method is compiled.
In other words, the overriding methods are implicitly marked with the
same ConditionalAttribute attribute as the virtual
method.
#define and
#undef apply only to preprocessor identifiers
within a file scope, whereas the /define: compiler
option defines preprocessor identifiers for all files in a project.
#define and #undef also take
precedence over the /define: compiler option. For
instance, if the project's
/define: compiler option defined
TRACE, and one of the files that project contains
has the code:
#undef TRACE
then TRACE will be defined for all files except
the one containing the #undef
TRACE directive.
To set the project's /define:
compiler option in Visual Studio .NET, right-click on the project
name in the Solution Explorer tool window, then click the Properties
menu item. This step will display the Property Pages dialog box for
this project. Next, click the Configuration Properties node in the
tree on the left side of this dialog box. In the control to the right
of this tree, find the line entitled Conditional Compilation
Constants. On this line, you may add or remove any preprocessor
identifiers that you want.
The #if and
#elif directives determine what code within a
member is to be compiled. For example:
public void MyMethod( )
{
#if (TRACE)
Method1( );
#elif (DEBUG)
Method2( );
#else
Method3( );
#endif
}
MyMethod will call Method1 when
TRACE is defined, Method2 is
called if TRACE is undefined and
DEBUG is defined, and Method3
is called if both TRACE and
DEBUG are undefined.
See Also
See the "C# Preprocessor
Directives" and
"ConditionalAttribute Class" topics
in the MSDN documentation.
|