Wednesday, September 7, 2016

C# : Conditional Attribute and #if Directive

In this post let’s see the use of Conditional attribute and how it differs from #if directive.

It’s always best to go by an example. Consider the following.

Example 1
using System;
using System.Diagnostics;
 
namespace ConditionalAttributeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            SayHello1();
        }
 
        static void SayHello1()
        {
            Console.WriteLine("Hello World 1");
        }
    }
}
It’s more than simple. If we run this “Hello World 1” will be printed on console. Now imagine that I want the method to be run only when a given condition satisfies. I know you can think of variety of ways to achieve that. But here the condition is based on a compilation symbol (DEBUG etc.).

Now let’s modify the code adding a compilation symbol named SOMETHING.

Example 2
#define SOMETHING
 
using System;
using System.Diagnostics;
 
namespace ConditionalAttributeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            SayHello1();
        }
 
        [Conditional("SOMETHING")]
        static void SayHello1()
        {
            Console.WriteLine("Hello World 1");
        }
    }
}
Now if we run this application, again "Hello World 1" will be printed on the console. And if we commented out the first line "#define SOMETHING", SayHello1() method will not get called thus the application will not print anything. It’s basically because the condition fails.

Now as you might aware, I can do the same using #if directive. Let’s modify the code to use #if.

Example 3
#define SOMETHING
 
using System;
 
namespace ConditionalAttributeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
#if SOMETHING
            SayHello1();
#endif
        }
 
        static void SayHello1()
        {
            Console.WriteLine("Hello World 1");
        }
    }
}
This will print “Hello World 1” and if we commented out the SOMETHING symbol, SayHello1() method will not get called. It’s basically Just as in Example 2. So now you must be wondering what’s the difference between Conditional attribute and #if directive. Let’s move on.

The first difference is, when you use #if, the code which is wrapped between #if and #endif, will only get compiled if the condition next to #if is true. Basically you can write almost anything within the #if and #endif and as long the condition is false, it will not throw any compilation errors (even if there are any).

The second and most important difference is, how IL is emitted in both these scenarios. When you use #if, the IL for code within the #if and #endif, will only get emitted if the given condition is true. Where as when you use Conditional attribute, IL will be emitted based on the method calls. Confused?, let’s go by the example. Let me modify the code to use both Conditional attribute and #if, and then let’s compare the IL which gets generated.

Example 4
#define SOMETHING
 
using System;
using System.Diagnostics;
 
namespace ConditionalAttributeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
#if SOMETHING
            SayHello1();
#endif
            SayHello2();
        }
 
        static void SayHello1()
        {
            Console.WriteLine("Hello World 1");
        }
 
        [Conditional("SOMETHING")]

        static void SayHello2()
        {
            Console.WriteLine("Hello World 2");
        }
    }
}
Now after compiling the code, let’s see what the generated IL is (here I am using ildasm.exe).

image
ildasm.exe
Here let’s see what we have for Main() method.

image
IL for Main()
You can see that IL is generated for two method calls SayHello1() and SayHello2(). Now let’s commented out the compilation symbol SOMETHING, compile the code and examine the emitted IL back again.

image
IL for Main()
Now there is nothing on SayHello1() and SayHello2() method calls in Main() method. Still no difference. Let’s come to this later in the post again.

Now let’s modify the code further as below.

Example 5
//#define SOMETHING
 
using System;
using System.Diagnostics;
 
namespace ConditionalAttributeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
#if SOMETHING
            SayHello1();
#endif
            SayHello2();
        }
 
        static void SayHello1()
        {
            Console.WriteLine("Hello World 1");
            SayHello3();
        }
 
        static void SayHello2()
        {
            Console.WriteLine("Hello World 2");
            SayHello3();
        }
 
        [Conditional("SOMETHING")]
        static void SayHello3()
        {
            Console.WriteLine("Hello World 3");
        }
    }
}
Take a note that, I have the first line commented out (otherwise, there won’t be any difference). Now let’s compile and examine the IL on Main() method back again.

image
IL for Main()
And now, you should be able to see a clear difference. There is nothing on SayHello1() method call, but you can see the IL code for SayHello2() method call.

The reason is, now the call to our conditional method (SayHello3()) is done through intermediate method (SayHello2()). And you can see, even if I use the same approach in #if scenario, but still no IL was generated for that.

And now the reason for IL code to be same on Example 4 is, in that case we were directly calling a conditional method (SayHello2()) from the Main() method. And since the condition is false, compiler knows it can’t call the SayHello2(). Because of that no IL code is generated for conditional (SayHello2()) method call.

Hope this post gives you a clear understanding on Compilation attribute and it’s difference between #if directive.

Happy Coding.

Regards,
Jaliya

1 comment: