Demystifying C# Programming’s ToString Method

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

The ToString method of the .NET framework object has a good set of useful features.

For. e.g. the ToString method is very useful as a formatting tool. This method and its overloads offer a ton of formatting functionalities, which makes other formatting practices redundant. This is possible through the string parameters that it accepts that tells the object how to format itself.

You can do simple stuff like padding to a string. Look below for a sample. The syntax shows that it takes a formatting expression in its overload.

  Syntax: myObject.ToString("{0}", " formatting expression"})

  string meF = String.Format("-{0,8}-", "me");
  string meB = String.Format("-{0,-8}-", "me");

The first one produces "- me-" and the second line produces "-me -"

The ToString implementations on an object can produce interesting and helpful results. One such object is the Querystring collection. If you have used the ToString implementation on the QueryString object, you would be amazed by the readable output that it presents.

For example, consider a page with three querystring objects ID, FirstName and Lastname. If you would use the Request.QueryString.ToString() on this page, the output would be similar to below:

  id=1&firstname=joe&lastname=kittle

It is well formatted and can be parsed easily. The well-formatted string is because of the ToString implementation of the underlying HttpValueCollection class.

We can also do formatting stuff like currency, decimals on numbers, etc. Refer to the references at the end of this article for some examples on these.

The QueryString's ToString implementation leads us to another important aspect: its importance in giving us quick info during debugging.

Debugging is almost a part of our life now. And Microsoft Visual Studio has improved a lot on its every version. The hover inspection and the dialogs that appear instantaneously are so helpful. The ToString method also plays an important role during debugging. You would have already noticed that when you are working with complex objects, these windows only display the qualified type name of the object. This is because the default ToString method is invoked by the dialogs, which results in the fully qualified type of the object.

Nevertheless, you can override the default ToString implementations to provide a meaningful display of the object in the quick watch and other debugger windows.

For. example, refer to the following class which has three properties.

   public class MyClass
       {
           /// <summary>
           /// Gets or sets the name.
           /// </summary>
           /// <value>The name.</value>
           private string Name { get; set; }

           /// <summary>
           /// Gets or sets the title.
           /// </summary>
           /// <value>The title.</value>
           private string Title { get; set; }

           /// <summary>
           /// Gets or sets the age.
           /// </summary>
           /// <value>The age.</value>
           private double Age { get; set; }

           /// <summary>
           /// Initializes a new instance of the <see cref="MyClass"/> class.
           /// </summary>
           public MyClass()
           { }

           /// <summary>
           /// Initializes a new instance of the <see cref="MyClass"/> class.
           /// </summary>
           /// <param name="name">The name.</param>
           /// <param name="title">The title.</param>
           /// <param name="age">The age.</param>
           public MyClass(string name, string title, double age)
           {
               Name  = name;
               Title = title;
               Age   = age;
           }
 

When an instance of this class is seen in the debugger windows, the below screen appears. Only the qualified type name appears.

 an instance of this class
Figure 1

Now, Let us override the ToString method to return the Name and the Age properties.

    	/// <summary>
           /// Returns a <see cref="System.String"/> that represents this instance.
           /// </summary>
           /// <returns>
           /// A <see cref="System.String"/> that represents this instance.
           /// </returns>
           public override string ToString()
           {
               return string.Format("Name = {0}, Age = {1}", Name, Age);
           }
 

And, if you see the instance of MyClass in the debugger windows, the formatted string appears.

the instance of MyClass in the debugger windows
Figure 2

Now, you know that when you are working with complex objects, the ToString overriding can be very useful and can save heaps of time.

The ToString method internally invokes the culture info to get the current culture and then uses the corresponding IFormatProvider to derive the culture-sensitive human readable string. The ToString overload takes a NumberFormatInfo instance, which can be provide a faster result.

The following excerpt is from http://dotnetperls.com/tostring.

excerpt
Figure 4

And remember, the ToString method can also cause your code to slowdown and prove inefficient. One such example worthy to be noted is from the same website as above: http://dotnetperls.com/string-for-loop

  using System;

  class Program
  {
      static void Main()
      {
          string input = "Dot Net Perls website";
          //
          // Check each character in the string using for-loop.
          //
          int spaces1 = 0;
          for (int i = 0; i < input.Length; i++)
          {
              if (input[i] == ' ')
              {
                  spaces1++;
              }
          }

          //
          // BAD: Check each character in the string with ToString calls.
          //
          int spaces2 = 0;
          for (int i = 0; i < input.Length; i++)
          {
              if (input[i].ToString() == " ") // NO
              {
                  spaces2++;
              }
          }
          //
          // Write results.
          //
          Console.WriteLine(spaces1);
          Console.WriteLine(spaces2);
      }
  }

And this excerpt from the same webpage explains why.

“Accessing characters with the string indexer. The first loop in the program text uses a three-part for-loop statement with an if-statement in the loop body. If the character is a space, the value stored in the spaces1 variable is incremented. In this way, the for-loop iterates over all characters in the string and counts the total number of spaces. No allocations on the managed heap occur and this is a well-performing loop over the string.

Converting each character to a new string. The second loop in the program text also uses a for-loop statement to iterate over the characters in the string. However, after accessing the character value, it calls the ToString method. This requires an allocation of a new string on the managed heap, because strings are reference types. Then, the op_Equality method is invoked on the two string instances in the loop body. This loop is much slower because it must allocate the strings and then use string comparisons. It has no advantages in this context.”

Hope this article was informative. Thanks for reading.

Related Articles

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read