Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Preprocessor Directives in C#

0.00/5 (No votes)
29 Feb 2012 1  
To explain Preprocessor directives in C#

Introduction

Preprocessor directives are commands that are interpreted by the compiler and affect the output or behavior of the build process. But the C# compiler does not have a separate preprocessor, like C and C++ you cannot use these directives to create macros. Preprocessing directives are top lines in our program that start with '#'. The '#' is followed by an identifier that is the directive name.

.NET framework 1.1 and above will support these preprocessor directives.

Classification of C# language preprocessor directives are as follows.

Conditional compilation: We can include and exclude parts of the program based on the conditions.

  • #if
  • #else
  • #elif
  • #endif
  • #define
  • #undef

Errors , Warnings , Line & pragma: The directive #error initiates the preprocessor to rise error, #warning like #error directive but it prompts warning to the user and continues with the process, #line can be used to hide sections of code from the debugger. The #pragma directive can either suppress or restore specific compiler warnings.

  • #warning
  • #error
  • #line
  • #pragma

Region: If you want to indicate a certain block of source code with a name, you can indicate it with a name and keep the entire block between #region and #endregion. So the C# code file is neatly organized as blocks, and that can be expanded or collapsed visually.

  • #region
  • #endregion

Real Time Usage

When I work with real time environment, the preprocessor directives are very helpful to set conditional compilation like setting up of default parameters based on the defined symbol, and prompting developers in terms of building project, and making conditional warnings and errors, etc.

Sample program to demonstrate it

#define Default
#define DevelopmentMode
#define TestingMode
#undef  Development

#if DEBUG
#warning You should not compile in debug mode, use release mode         
#endif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SampleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            String orgName=String.Empty;
            String email=String.Empty;
            String SourceDb=String.Empty;

            #if(DevelopmentMode)
              {
              SourceDb="C:\\DovDb.Mdb"; //This Db used at the time of development phase
              }
            #else
              {
              SourceDb = "C:\\TestDb.Mdb";//This Db used at the time of testing
              }
            #endif


            #if(Default)
            {
                orgName = "MyOrganization";            
                email = "Default@gmail.com";
                const string logName = @"\myLog.log";  //Write log information
            }
            #else
            {   
                orgName = fetch from database
                email = fetch from database
               const string logName = fetch from database //Write log information
            }
            #endif
        }       
    }
}

Preprocessor directives help the developer to make programming with minimal complexity, improving readability, ease Of maintenance, and prompting invalid changes in the flow of code, etc.

Using the Code

I am going to provide a simple application which will enable you to better understand preprocessor directives in C#, and how we can use it in the real time environment.

In the following, there are 3 private assemblies, viz., version0, version1 and version2. Version0 takes input data from the user. A new feature “AddOperation” is added in Version1 based on the user input values. Version2 has added new feature “SubOperation” and changed the existing “AddOperation” with the default values.

So the users who are going to use “AddOperation” based on the user input values can use version2, but they don’t get the new feature of “SubOperation”.

The following code demonstrates it.

Version0

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreproDirective
{
    class NumberOperationVersion0
    {
        Int32 x, y;
        public void GetData(Int32 x, Int32 y)
        {
            this.x = x;
            this.y = y;

        }
        public Int32 AddOperation()
        {
            //Not implemented
            return 0;
        }

        public Int32 SubOperation()
        {
            //Not implemented
            return 0;
        }
    }
}

The above version0 has the feature to take data from the user but does not have any operations.

Version1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreproDirective
{
    public class NumberOperationVersion1
    {
        Int32 x, y;
        public void GetData(Int32 x,Int32 y)
        {
            this.x = x;
            this.y = y;
        }
        public Int32 AddOperation() 
        {
    //Operation performed based on User input values 
            return x + y;
        }
        public Int32 SubOperation()
        {
            //Not implemented in this version1
            return 0;
        }
    }
}

This version1 adds "AddOperation" feature by taking user input.

Version2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PreproDirective
{
    public class NumberOperationVersion2
    {
        Int32 x, y;
        public void GetData(Int32 x,Int32 y)
        {
            this.x = x;
            this.y = y;
        }

        public Int32 AddOperation(Int32 x,Int32 y)
        {
//Operation performed based on default values passed from main program
            return x + y;
        }

        public Int32 SubOperation()
        {
            return x-y;
        }           
    }
}

This version2 implemented the feature "SubOperation", and changed "AddOperation" by taking default values.

Main Program

#define version0   
#define version1
#define version2
#undef  version0      // if you comment it,  error raised

#if DEBUG
#warning Compiled in DEBUG mode.      // use release mode to prevent this warning
#endif

#if version0
#error Version0 is not working.    //Error will be raised when version0 is defined
#endif

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreproDirective
{
    class Program
    {
        static void Main(string[] args)
        {
            Int32 x=0,y=0;

                #pragma warning disable
                       #line 20 "NumberOperationVersion1.cs"
                       #warning "Changes in Earlier versions are not allowed"
                       #line default
                #pragma warning restore

                #line 20 "NumberOperationVersion0.cs"
                #warning "Changes in version0 are not allowed"
                #line default

            //Version 1 changes
            #region V1
                    #if(version1)
                    {
                       NumberOperationVersion1 objVer1=new NumberOperationVersion1();
                       Console.WriteLine("Enter Xvalue,Yvalue to check version1
                       compatibility with ADD and Sub Operation");
                        
                        Console.WriteLine("Enter Xvalue:");
                        x=Convert.ToInt32(Console.ReadLine());

                        Console.WriteLine("Enter Yvalue:");
                        y = Convert.ToInt32(Console.ReadLine());
                        objVer1.GetData(x,y);
                    Console.WriteLine("AddOperation Result is:"+objVer1.AddOperation());
              Console.WriteLine("SubOperation is not working with this version \n\n\n\n");
                    }
                    #endif
            #endregion V1

             //Version 2 changes
            #region V2                              

                     #if (version2)
                       {
                         NumberOperationVersion2 objVer2=new NumberOperationVersion2();
                         Console.WriteLine("Enter Xvalue,Yvalue to check version2
                         compatibility with ADD and Sub Operation");
                         Console.WriteLine("Enter Xvalue:");
                         x = Convert.ToInt32(Console.ReadLine());

                         Console.WriteLine("Enter Yvalue:");
                         y = Convert.ToInt32(Console.ReadLine());
                         objVer2.GetData(x,y);
                        Console.WriteLine("AddOperation Result is(Based on the default
                        values version-2 is):"+objVer2.AddOperation(10,12));
                        Console.WriteLine("SubOperation Result is (Based on user input):"+
                        objVer2.SubOperation());
                    }
                    #else
                    {
                      Console.WriteLine("No Version found");
                    }
                    #endif

            #endregion V2                     
            Console.ReadKey();
        }
    }
}

On the top of the program, versions are defined, and the unused version0 is undefined.

#if DEBUG
#warning Compiled in DEBUG mode.
#endif 

If we run the application in debug mode, it will throw a warning as shown in Fig.1.

#if version0
#error Version0 is not working.    
#endif

If version0 is defined but unused, so it should be reversed to undefined; lest it will throw a fatal error as "Version0 is not working" shown in the Fig.1:

Fig-1
#pragma warning disable
#line 20 "NumberOperationVersion1.cs"
#warning "Changes in Earlier versions are not allowed"
#line default
#pragma warning restore 

In the main program, the above statement throws a warning at line number 20 in "NumberOperationVersion1.cs" class. But the statement “#pragma warning disable” will disable the warning.

#line 20 "NumberOperationVersion0.cs"
#warning "Changes in version0 are not allowed"
#line default

Statement throws warning at line number 20 in "NumberOperationVersion0.cs" class:

Fig-2

The regions can be understood from the following figure:

Fig-3

The above program is taken to easily illustrate the working of preprocessor directives.

Conclusion

This article gives you a better understanding of preprocessor directives in C#. Hope to get your feedback and suggestions.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here