Wednesday, September 23, 2015

C# - Debugger Attributes Explained with Examples

1. Introduction

In the last article, we saw about Logging and getting function call stack information. In this article, we will see “Debugger Attributes” which controls debugging ability and provide a rich experience to the debugging user. An "Attribute" is a Tag defined over the elements like Class, Functions, assemblies etc. These tags determine how the elements should behave at run time. Let us see below specified debugging attributes with a simple example:


  1. DebuggerBrowsable Attribute
  2. DebuggerDisplay Attribute
  3. DebuggerHidden Attribute


2. About the Example

The example used in this article is shown in the screenshot below:

DebuggerAttributes Fig.1
Fig 1. Debugger Attributes Example

In each button click handler, the debugger breakpoint is invoked dynamically and hence it is advised to launch the application through "VisualStudio" with F5 (i.e.) start the application through the menu option Debug->Start Debugging. Once you download this example application, watch the video which demonstrates the usage of each attribute.

3. The Book Class

First a class called Book is defined to demonstrate the debugging attributes. This class has three private members and constructor to initialize those private members. The code for the class is given below:

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

namespace DebugAttrib
{
    //Sample 01: Default Book Class
    class Book
    {
        private int m_bookid;
        private String m_bookname;
        private String m_author;

        public Book(Int32 idno, String bookname, String Author)
        {
            m_bookid = idno;
            m_bookname = bookname;
            m_author = Author;
        }
    }
}

4. Default Behaviour of Book Class

The “Default Class” button click handler examines the behaviour of the above-specified book class. In the form file, to break into the code dynamically for debugging, the Diagnosis namespace is used. The Code is given below:

//Sample 02: Required NameSpace
using System.Diagnostics;

The “Default Class” button click handler creates the instance of Book in order to examine the default behaviour. The code is below:

//Sample 03: Class Default in Auto Window
private void btnDefault_Click(object sender, EventArgs e)
{
    Debugger.Break();
    Book bk = new Book(110, "C++ for Starters", "Rob Kati");
}

When you debug the class instance “bk”, you can see all the member information in the debugger window. Also, the debugger shows the Namespace and Class Name in the instance level. Have a look at the below video to know the default behaviour of the Book Class Instance:

Video 1: Default Book Class Behaviour



5. Book class behaviour with ToString Override

Once you override the "ToString() Method" in the class, the debugger knows how to translate the class in the string format. During the debug time, the ToString implementation provided by us will be invoked by the debugger. Have a look at the below code:

//Sample 04a: Override ToString
public override string ToString()
{
    return string.Format("{0}[{1}] by {2}", m_bookname, m_bookid, m_author);
}

In the above code, a string is formed based on the members present in the class and that string is returned to the caller.  In the debugger output, we can now see the meaningful information against the class Instance Name instead of the default "Namespace.ClassName" as it is already displayed under the "Type" column.


6. DebuggerBrowsable Attribute

There are various windows like Auto, Quick watch etc can browse the class information and examine the values in each member. The "DebuggerBrowsable Attribute" controls what information can be browse-able through the debugger. To demonstrate the debugger browsable attribute, the default Book class is shown in the previous section is modified and the modified version of the book class is Book1. Have a look at the Book1 class below:

//Sample 05: Copy Pasted Book class. Look @ 4.x for the Modifications
class Book1
{
    //Sample 5.1: Change all private member as public
    public int m_bookid;
    public String m_bookname;
    public String m_author;

    //Sample 5.2: Add a Private Member and Check Attribute
    // Sample 7.0: Add the Attrubute
    [ DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private String m_publisher;
   

    //Sample 5.3: Add new member to constructor
    public Book1(Int32 idno, String bookname, String Author, String publication)
    {
        m_bookid = idno;
        m_bookname = bookname;
        m_author = Author;

        //Sample 5.4: Initialize the Private Member
        m_publisher = publication;
    }

    //Sample 04b: Override ToString
    public override string ToString()
    {
        return string.Format("{0} by {1} from {2}", m_bookname, m_author, m_publisher);
    }
}

In the above code, notice the member “m_publisher” is marked with DebuggerBrowsable attribute. Here, we set "DebuggerBrowsableState.Never" through the DebuggerBrowsable attribute. The never state informs the runtime that the member should not be browse-able while debugging any instance of the class Book1. There are other browse-able states and those are listed below:
  1. Collapsed - Shows the element as collapsed.
  2. Never - Never show the element.
  3. RootHidden - Do not display the root element; display the child elements if the element is a collection or array of items.

In the Main form, “Browsable” button click handler is provided to test the class Book1. The code is given below:

//Sample 06: Debug and check Browsable attribute
private void btnBrowse_Click(object sender, EventArgs e)
{
    Debugger.Break();
    Book1 bk = new Book1(110, "C++ for Starters", "Rob Kati", "KPB");
}

Video 2: Browsable Attribute and effect of ToString Override



7. DebuggerDisplay Attribute

The debugger display attribute can be marked for elements like class, functions, properties etc. Consider the below screen shot:

DebuggerAttributes Fig.2
Fig 2. DebuggerDisplay Attribute

Here, the "DebuggerDisplay Attribute" is defined for the class member m_author.  The attribute is marked as 1 in the above picture and the attribute takes a string. Note that Debugger display string is accessing the class member within curly basis (Marked as 2). At runtime, the value will be substituted from the actual variable m_author (marked as 3). To examine the above attribute, the basic Book class is modified to have Book2 class. In Book2 class, all three data members are marked with DebuggerDisplay attribute. The code is shown below:


//Sample 08: Changed Class Name as Book2
class Book2
{
    //Sample 09: Add Attributes to Private Member
    [DebuggerDisplay("Book ID is {m_bookid}.")]
    private int m_bookid;

    [DebuggerDisplay("Book Title is {m_bookname}")]
    private String m_bookname;

    [DebuggerDisplay("Written by {m_author}")]
    private String m_author;

In the Main form, Click event for the button “Debugger Display” is handled. The event handler code is listed below:

//Sample 10: Debugger Display Attribute
private void btnDebuggerDisplay_Click(object sender, EventArgs e)
{
    Debugger.Break();
    Book2 bk = new Book2(110, "C++ for Starters", "Rob Kati");
}

Video 3: DebuggerDisplay Attribute in action



8. DebuggerHidden Attribute

When you mark a member function with this attribute the debugger will not stop on that method; that means you can’t keep a breakpoint on that method. To check this attribute, the Book2 class is modified to have a new method called GetPrice which returns different price based on the month-Range in a year. Since the GetPrice is marked with "DebuggerHidden Attribute" we can’t debug this particular function in the Book2 class. The code is given below:

//Sample 11: Get Price of the book
//Sample 13: Add the Hidden Attribute
[DebuggerHidden()]
public double GetPrice()
{
    DateTime today = DateTime.Now;
    if (today.Month > 0 && today.Month < 5)
        return 500.50;
    else if (today.Month > 4 && today.Month < 10)
        return 805.00;
    else
        return 200.20;
}

The “Hide Function” button click event handler creates the Instance of Book2 and makes a call to GetPrice. You can examine the function to see how debugging is prohibited for the GetPrice. Below is code for button click event handler:

//Sample 12: Debugger Hidden Attribute
private void btnDebuggerFnHide_Click(object sender, EventArgs e)
{
    Debugger.Break();
    Book2 bk = new Book2(110, "C++ for Starters", "Rob Kati");
    double price = bk.GetPrice();
    Debugger.Log(0, "Information", string.Format("Price={0}", price));
}

Video 4: Checking the DebuggerHidden Attribute





Source code : Download

Saturday, September 12, 2015

C# - Using Debugger Break, Log and getting Stack Trace

1. Introduction

The "Debugger Class" is availble under System.Diagnostics name space which will help us in easy diagnostics of the application. In this article we will examine the usage of the debugger class and using that we will see breaking through the code, logging and dynamically taking the snap-shot of the call stack.

2. About the example

The screenshot of the sample application is shown below:

C# Print StackTrace Example - Screenshot

The textbox marked as 1, shows the status of the debugger. When the application is attached with the debugger, the status shows attached. Clicking the refresh button (Marked as 2) updates the debugger status. Clicking the Break On Code button (Marked as 3) dynamically breaks the application as breakpoint is hit. This is useful when you want to break the application without the breakpoint. Clicking the Debug Log (marked as 4) button produces the log entries in the debug output window. In the same debug output window, the application call stack is printed whenever the Output Stack Trace button (Marked as 5) is clicked.

The sample application uses functionalities provided System.Diagnostics namespace.

3. Checking the debugger status

The status of the debugger can be checked using the "IsAttached Property" of the "Debugger Class". When the application is attached to the debugger, this property is set to true. By making use of this below specified function is written:

//Sample 02: Set state of the debugger
public void SetDebuggerState()
{
    if (Debugger.IsAttached == true)
        txtDebuggerState.Text = "Attached";
    else
        txtDebuggerState.Text = "Not Attached";
}
This function is called in the form load as well as Refresh button click handler. The function after checking the debugger state indicates status of the debugger in the “debugger state” textbox. Below is the code which makes use the SetDebuggerState function:

private void frmDebugAttr_Load(object sender, EventArgs e)
{
    //Sample 03a:Check the State of the Debugger
    SetDebuggerState();
}

private void cmdRefresh_Click(object sender, EventArgs e)
{
    //Sample 03b:Check the State of the Debugger
    SetDebuggerState();
}

Below is the video which checks the status with and without the debugger.


Video 1: Checking the Debugger State




4. Dynamically Breaking on the Code

The "break() Method" of the debugger class is used to break the application dynamically. At runtime when the function break is called, the code breaks at the call to the break. This happens when the debugger is already attached. Otherwise, a window appears stating; user break point encountered and asks you to select the debugger among the list available debugger in the machine. Below is code which breaks the application dynamically:

private void btnBreakOnCode_Click(object sender, EventArgs e)
{
    //Sample 04: Break on the Code
    if (Debugger.IsAttached == true)
        Debugger.Break();
    int x = 15;
    int y = x + 5;
}

In the above code, the Break is called only when the debugger is attached to the application. Have a look at the below video to see how we break into the code without the break point:

Video 2: Breaking into code dynamically




5. Log Debug information on Output Window

The "Log() function" of the "debugger class" is used to log the debugging information on the output window. This method does not perform any action when debugger is not attached to the application. Have a look at the below piece of code:

private void btnDebugLog_Click(object sender, EventArgs e)
{
    int x = 15;
    //Sample 05: Log informations
    if (Debugger.IsAttached == true)
    {
        Debugger.Break();
        string LogString = String.Format("Value in x = {0}", x);
        string newline = System.Environment.NewLine;
        Debugger.Log(0, "Information", "Debugger Attached" + newline);
        Debugger.Log(0, "Information", LogString + newline);

    }
}

Here, we are first checking the debugger is attached or not. When debugger is in attached state, we dynamically breaking the code by calling "Debugger.Break()". After that two we are forming the Log information to examine the content of the variable x. Finally the call to "Debugger.Log()", flushes the log information to the output window of the debugger. The below video shows the Log information on the output window:

Video 3: Logging Custom Information



6. Logging Function call stack to Output Window  


Sometimes we may need to log the function call stack in a log file. The call stack information is useful when it is logged in the exception handlers. The "StackTrace Class" will give us the snapshot of the function call order. Once the snapshot is available, other call related information can be retrieved from "StackFrame". The code for the “Output Stack Trace” button click handler is given below:

//Sample 06: Getting Stack Trace Information
private void btnStackTrace_Click(object sender, EventArgs e)
{
    DispoutCallStack();
}

It is obvious that we are making call to a function DispoutCallStack(). Inside this function, the function call stack information is logged into the output window. Code for this function is given below:

//Sample 06: Getting Stack Trace Information
public void DispoutCallStack()
{
    //Sample 6.1: Get Total number of functions
    StackTrace trace = new StackTrace(true);
    int total = trace.FrameCount;

    for (int Frame_index = 0; Frame_index < total; Frame_index++)
    {
        //Sample 6.2: Iterate through each stack frame and display the info
        StackFrame frame = trace.GetFrame(Frame_index);
        String StackLine = String.Format("[{0}], Func:" +
        "{1}, FileName: {2}[{3}]", Frame_index,
        frame.GetMethod(),
        frame.GetFileName(),
        frame.GetFileLineNumber());

        //Sample 6.3: Display Stack Trace Information on output Window
        Debugger.Log(0, "Information", StackLine);
        Debugger.Log(0, "Information", Environment.NewLine);
    }
}

In the function, the trace instance of type StackTrace is created and here we get the entire stack frame in a collection. Next in a for loop we retrieve the Stack Frames one by one and in each iteration, the retrieved StackFrame information is used to collect the other call related information. The collected information is stored in a string variable StackLine and then this stack line is displayed in the output window using the technique that we saw in the previous section. Have a look at the below video to see how the Function call stack information is displayed in the output window:

Video 4: Logging Function Call Stack

Source Code: Download

Like this site? Tell it to your Firend :)