Question on Item 4
MSDN uses a different idiom to support multiple conditions on an attribute. I think it has a number of shortcomings.Question: Marc Jennings writes:
In the section on Conditionals you say that in order to create a method that will fire if more than one condition is true (logical AND), you need to use
#if (VAR1 && VAR2)
#define BOTH
#endif
However, it is possible to chain the conditionals together (according to MSDN, anyway…)
<QUOTE from=”MSDN”>
[Conditional("A")] public static void IfAandB( )
{
AandBPrivate( );
}
[Conditional("B")] static void AandBPrivate( )
{
/* Code to execute when both A and B are defined... */
}
Call IfAandB; if both A and B are defined, AandBPrivate will execute.
</QUOTE>
Is there any reason to use your method above the MS one?
Answer:
I chose using the #if logic over chaining conditionals because it produces code that is much easier to maintain.
Using the idiom I preferred, the MSDN sample would look like this:
#if (A && B)
#define BOTH
#endif
[Conditional("BOTH")] static void AandBPrivate( )
{
/* Code to execute when both A and B are defined... */
}
I look at the top of the file to find any defined environment variables. And, the single environment variable used to control the compilation of a function is found on the method in question. The sample from MSDN can be perverted in a couple ways. First, I can easily circumvent the first check:
/* No conditional attribute */ static void BPrivate( )
{
AandBPrivate( );
}
The code inside AandBPrivate() can be accessed when only B is defined. That certainly looks like it was not intended.
The MSDN idiom does not scale well either. Putting the Boolean logic in the conditional, I can easily create more complicated expressions:
#if (A && B && C && D)
#define ALL
#endif
To do the same thing following the MSDN idiom requires this:
[Conditional("A")] public static void IfAandB( )
{
AandBPrivate( );
}
[Conditional("B")] static void AandBPrivate( )
{
AandBAndCPrivate( );
}
[Conditional("C")] static void AandBandCPrivate( )
{
AandBAndCandDPrivate( );
}
[Conditional("D")] static void AandBandCandDPrivate( )
{
AandBAndCandDPrivate( );
}
It gets maddening fairly quickly.
Finally, putting the conditionals at the top of the file means I can add methods that are dependent on the absence of an environment variable, which is not supported by the conditional attribute:
#if ( ! D )
#define NotD
#endif
[Conditional("NotD")] static void NotDPrivate( )
{
/* contents elided. */
}