Preprocessor Directives & .NET XML Documentation

Discussion in 'C#' started by shabbir, Feb 18, 2014.

  1. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    .NET framework has everything what it takes to develop a highly customizable software application. Apart from providing thousands of built in classes in language library and common language runtime, .NET offers variety of options during code compilation. Using visual studio you can access those options via user interface. However, there are certain compilation features that need to be integrated in code. This is where preprocessor directives play important role. In this article we are going to throw light upon preprocessor directives. In addition to preprocessor directives, another important feature that allows proper documentation of C# code is that of XML documentation. XML is the medium of transferring information over the internet. Therefore, it is always a good practice to document your C# code in XML. We will show how to do this in this article. But before that, let us start our discussion with preprocessor directives.

    Preprocessor Directives



    Preprocessor directives in simplest words are the directives which affect the output behavior of the compiled code. These directives actually tell the compiler at run time about the regions of the code and how should they be compiled. Unlike C and C++, C# doesn’t contain any separate preprocessors which can be employed to create macros from directives. Preprocessor directives are supported by .NET framework 1.1 and above.

    Preprocessor directives are simple to define. Preprocessor directives start with a hash sign ‘#’ followed by the name of the directive. Preprocessor directives can be used to perform variety of operations few of which are as follows.

    Conditional Compilation

    Preprocess directives allows us to set conditions during code compilation. We can tell the compiler that exclude or include following lines of code while you are compiling the code. The conditional preprocessor directives available in C# are #if, #else, #elif, #define, #undefine, #endif.

    Errors & Warnings

    Following preprocessors are used for signaling warnings and errors.
    • #error: Initiates the process of raising error during preprocessing.
    • #warning: Warnings are similar to errors but they only warn the user and continue the process.
    • #line: These are the directives that are used to hide a section of code during compilation.
    • #pragma: This directive is used to restore or suppress compiler warnings.
    Specifying Regions

    In order to more effectively organize your code, you can give a name to a certain block of your source code. You can collapse and expand that piece of code via region preprocessors. There are two preprocessors used for this purpose: #region and #endregion.

    Now when we have theoretically explained the concept of preprocessor directives, let us put this concept into practice. Have a look at Example1 to further grasp the concept of preprocessor directive.

    Code:
    #define DEBUG
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    
    namespace CSharpTutorial
    {
        class PrePro
        {
            static void Main()
            {
    # if (DEBUG)
                Console.WriteLine("Code withing DEBUG directive");
    
    #elif EXPERT
              Console.WriteLine("Code withing Expert directive");
    #endif
               Console.ReadLine();
            }
        }
    }
    
    Have a look at Example1; you need to make sure that you put the directive at the top of your file. Even before importing the namespaces. Another thing needs to be kept in mind is that there should be only one preprocessor directive in each line. Another important thing to notice here is that preprocessor directives are not ordinary statements, therefore there is no need to append semicolon at the end of the preprocessor directive as we do with ordinary statement. Keep these rules in mind while using preprocessor directives in your program.

    Now let us come back to our code in Example1, we have defined a preprocessor directive #define DEBUG. Now, we if we pass the DEBUG expression to conditional preprocessor directive, it will evaluate to true and the statements within the ‘if’ conditions will execute. Now come inside the main method, here we have put a conditional preprocessor directive and which tells the compiler that if the code is being compiled in DEBUG mode and DEBUG directive has been defined in the application, then include these statements in the compiled code, otherwise ignore these statements. The compiler will check that #define DEBUG has been defined at the top of the code therefore it will execute that piece of code. The statement after the preprocessor directive #else would not execute because we have DEBUG directive at the top of our file. The output of our code will be as follows.

    Output1

    [​IMG]

    Or '||', and '&&' and not '!' operators can also be used along with conditional preprocessor directives. This concept will be elaborated with the help of another example. Have a look at the code in Example2.

    Example2
    Code:
    #define DEBUG
    #define RELEASE
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    
    namespace CSharpTutorial
    {
        class PrePro
        {
       
          static void Main()
            {
    #if (DEBUG && !RELEASE)
             Console.WriteLine("Code within DEBUG block");
    #elif (!DEBUG && RELEASE)
             Console.WriteLine("code within RELEASE block");
    #elif (DEBUG && RELEASE)
                Console.WriteLine("code within RELEASE and DEBUG block");
    #else
             Console.WriteLine("DEBUG and RELEASE are not defined");
    #endif
                Console.ReadLine();
            }
        }
    }
    
    In Example2, we have defined two preprocessor directives at the beginning of our file namely, DEBUG and RELEASE. Now inside the main function we have used conditional preprocessor directive to include and exclude the blocks of code. First we set condition that if DEBUG is defined and RELEASE is not defined, execute the code. Next we set the opposite condition that if DEGBU is not defined but RELEASE is defined, execute that code. Since, both DEBUG and RELEASE are defined, therefore these preprocessor conditions will evaluate to false. Next we have set a condition that if both DEBUG and RELEASE are defined, execute this bit of code. This statement would execute and printed. In this way we can use preprocessor directives to exclude and include code in our application even before compilation. Preprocessor directives are extremely powerful feature if used intelligently.

    XML Documentation



    Importance of documenting code is enormous. Documentation helps stakeholder, particularly developers to share information about the modules, blocks, types and members of code. Documentation is basically set of information, in the form of comment that describes a particular type, member, module or any piece of code in your application.

    There are two way to add comments to your application. One is the traditional way to add comments where you simply put a double slash ‘//’ and write a single line comment against any piece of code or you use /* some comment …… */ to write double line comments. These comments are good for documenting short information that can be read while modifying the code. However, to automatically generate documentation from code and to build an XML documentation file for code, you need to document your code using XML documentation syntax which we will explain in this section.

    An XML single line comment begins with a triple slash, followed by some tags. For example,
    Code:
    /// <summary> This method will set the price of a car </summary>
    public void SetPrice (….) 
    
    The above comment can also be added as a multiline comment as
    Code:
    /// <summary>
    /// this method will set the price of a car 
    /// </summary>
    
    Another way to add above comment is using multiline XML documentation technique i.e
    Code:
    /**
    this method will set the price of a car
    */
    
    At the moment, XML documentation might not look pleasing to the eyes but it has many potential advantages which we will see in our next example. So pay particular attention to our next example i.e. Example3.

    Have a look at Example3. Create a Visual Studio 2010 console application and place this code in a separate file. Or you can also place this code in the same file where the class containing the main method is located.

    Example3 (Part1)

    Code:
        /// <summary>
        /// A Car with a name, model and engine capacity.
        /// </summary>
        class Car
        {
            /// <summary>
            /// Read-only property for the car's name
            /// </summary>
            private readonly string carname;
    
            /// <summary>
            /// The name of the Car
            /// </summary>
            public string CarName { get { return carname; } }
    
            /// <summary>
            /// R Read-only property for the car's model
            /// </summary>
            private readonly int model;
    
            /// <summary>
            /// The Car's model
            /// </summary>
            public int Model { get { return model; } }
    
            /// <summary>
            /// The Car's price
            /// </summary>
            public int price;
    
            /// <summary>
            /// The engine capacity of the Car
            /// </summary>
            public int Engine { get; private set; }
    
            /// <summary>
            /// The constructor sets the name, model and Engine of the car
            /// </summary>
            /// <param name="name">The name of the Car</param>
            /// <param name="model">The Car's model</param>
            /// <param name="Engine">The engine capacity of car</param>
            public Car(string name, int model, int Engine)
            {
                this.carname = name;
                this.model = model;
                this.Engine = Engine;
            }
    
            public override string ToString()
            {
                return String.Format("{0} is {1} model old and has {2} engine capacity", CarName, model, Engine);
            }
    
            /// <summary>
            /// Sets Price of the car
            /// </summary>
            /// <param name="price">The price of the car</param>
        
            public void SetCarPrice(int price)
            {
                this.price = price;
         
            }
        }
    
    The code is extremely simple to comprehend. But the things which actually matter are the documentation you are seeing throughout the code. We have defined a class named car but before that we commented the summary of what car class contains using the XML documentation. Similarly before each private member field and the corresponding property we commented the summary. Also, you can see that we commented the parameters that method would take using param tag of the XML documentation as we did with the constructor of the class. Similarly, we commented the summary of the of SetCarPrice method along with the details of the parameter that this method would take using the XML documentation.

    Now, you must be wondering what the advantages of XML documentation are. To see the advantage that XML documentation brings with it, add the following class in the same namespace in which you created the car class or you can add this class in the same file as of Car class’s file. This class contains the main method and would show you a glimpse of the power of XML documentation

    Example1 (Part2)

    Code:
    
        class Program
        {
          static void Main()
            {
    
                Car car= new Car("Audi", 2014, 3500);
                car.SetCarPrice(300000);
                Console.WriteLine(car);
                Console.Read();
    
            }
        }
    
    When you type car, you will see that visual studio IntelliSense would show the detail of the Car type, this detail is the same as we commented in the summary of the XML comment before the defining class car in Example1 (Part1). Following figure shows that.

    [​IMG]

    Similarly, when you declare an object of Car class, when you type the new followed by the type name, Visual Studio will use its IntelliSense feature to display the summary of the constructor that we commented in part1 of Example1. Also the detail of the parameter that we have to pass is available as shown in the following figure where the detail of the parameter ‘name’ is given. This detail is the same as we commented in XML documentation’s param tag, before defining the constructor which is as follows.

    Code:
            /// <summary>
            /// The constructor sets the name, model and Engine of the car
            /// </summary>
            /// <param name="name">The name of the Car</param>
            /// <param name="model">The Car's model</param>
            /// <param name="Engine">The engine capacity of car</param>
            public Car(string name, int model, int Engine)
            {
                this.carname = name;
                this.model = model;
                this.Engine = Engine;
            }
    
    [​IMG]

    The first advantage of XML documentation is the IntelliSense feature which gets activated on the types for which you write XML documentation. Another great advantage of XML documentation is that you can automatically generate a documentation file that contains all the XML comments of the application. This file can be used to generate HTML based documentation for your application that can be used over the internet.

    In order to generate an XML documentation file for the application, you need to follow these steps.
    1. Right click on the project name and choose properties.
    2. Click the build tab on the options on the left side of the properties menu.
    3. On that page, you will find a check box “XML documentation file” at the end of the page. Check that.
    4. Rebuild your code and go to your bin/debug folder. You will find an XML file that you named when you checked the “XML documentation file” check box. The fill would contain all the comments that you added to your application.
     
    Last edited: Jan 21, 2017

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice