CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

David Hayden [MVP C#]

         .NET Tutorials, Patterns, and Practices

Overriding System.Object.ToString() and IFormattable

A couple of days ago I discussed overriding System.Object.Equals(Object obj) in a post called Object Identity vs. Object Equality - Overriding System.Object.Equals(Object obj).  The gist of that post is essentially that when you create new classes that inherit from System.Object, you may want to consider overriding System.Object's virtual methods so that they make sense for your class.  In that article we had overriden Equals and GetHashCode for the Customer class to suit our needs for equality.

In continuing this idea, System.Object also has a virtual ToString() method that we inherit in our classes.  I find this an absolute must to override, because the method provided by System.Object only returns the name of the class.  Hence the output of the following code will just be "Person."

Not Overriding ToString()

using System;

public class Person
{
    #region Private Members

    private string _firstname;
    private string _lastname;
    private int _age;

    #endregion

    #region Properties

    public string Firstname
    {
        get { return _firstname; }
        set { _firstname = value; }
    }

    public string Lastname
    {
        get { return _lastname; }
        set { _lastname = value; }
    }

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }

    #endregion

    #region Contructors

    public Person (string firstname, string lastname, int age)
    {
        if (firstname == null || firstname.Length == 0)
            throw new ArgumentNullException("firstname");

        if (lastname == null || lastname.Length == 0)
            throw new ArgumentNullException("lastname");

        _firstname = firstname;
        _lastname = lastname;
        _age = age;
    }

    #endregion
}

public class TestClass
{
    public static void Main()
    {
        Person p = new Person("David","Hayden",99);
        Console.WriteLine(p); // Outputs "Person"
        Console.ReadLine();
    }
}

That is pretty useless for debugging or anythine else.  By simply overriding ToString(), we can get something a bit more useful.  When we run the new version of our code shown below, we get the following output: "David Hayden, Age = 99".

Overriding ToString()
using System;

public class Person
{
    #region Private Members

    private string _firstname;
    private string _lastname;
    private int _age;

    #endregion

    #region Properties

    public string Firstname
    {
        get { return _firstname; }
        set { _firstname = value; }
    }

    public string Lastname
    {
        get { return _lastname; }
        set { _lastname = value; }
    }

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }

    #endregion

    #region Contructors

    public Person (string firstname, string lastname, int age)
    {
        if (firstname == null || firstname.Length == 0)
            throw new ArgumentNullException("firstname");

        if (lastname == null || lastname.Length == 0)
            throw new ArgumentNullException("lastname");

        _firstname = firstname;
        _lastname = lastname;
        _age = age;
    }

    #endregion
    
    public override string ToString()
    {
        return String.Format("{0} {1}, Age = {2}", _firstname,
                               _lastname, _age.ToString());
    }
}

public class TestClass
{
    public static void Main()
    {
        Person p = new Person("David","Hayden",99);
        Console.WriteLine(p); // Outputs "David Hayden, Age = 99"
        Console.ReadLine();
    }
}

So now we are cooking.  However, in the real world, we need way more flexibility in how we want to display this person.  This is where the interface IFormattable comes in.  IFormattable is as basic as you can get.  It has one method:

IFormattable

public string ToString(string format, IFormatProvider formatProvider);

By having our person class implement IFormattable, we can display this person class in a multitude of formats:

Implementing IFormattable
using System;

public class Person : IFormattable
{
    #region Private Members

    private string _firstname;
    private string _lastname;
    private int _age;

    #endregion

    #region Properties

    public string Firstname
    {
        get { return _firstname; }
        set { _firstname = value; }
    }

    public string Lastname
    {
        get { return _lastname; }
        set { _lastname = value; }
    }

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }

    #endregion

    #region Contructors

    public Person (string firstname, string lastname, int age)
    {
        if (firstname == null || firstname.Length == 0)
            throw new ArgumentNullException("firstname");

        if (lastname == null || lastname.Length == 0)
            throw new ArgumentNullException("lastname");

        _firstname = firstname;
        _lastname = lastname;
        _age = age;
    }

    #endregion

    #region IFormattable Members

    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (format == null) format = "G";

        if (formatProvider != null)
        {
            ICustomFormatter formatter = formatProvider.GetFormat(
                this.GetType())
                as ICustomFormatter;

            if (formatter != null)
                return formatter.Format(format, this, formatProvider);
        }

        switch(format)
        {
            case "f" : return _firstname;
            case "l" : return _lastname;
            case "na" : return string.Format("{0} {1} Age= {2}",
                        _firstname, _lastname, _age.ToString());
            case "n" :
            case "G" :
            default : return string.Format("{0} {1}",
                              _firstname, _lastname);
        }
    }

    #endregion

    public override string ToString()
    {
        return ToString("G", null);
    }

    public string ToString(string format)
    {
        return ToString(format, null);
    }

    public string ToString(IFormatProvider formatProvider)
    {
        return ToString(null, formatProvider);
    }
}

public class TestClass
{
    public static void Main()
    {
        Person p = new Person("David","Hayden",99);
        Console.WriteLine("{0}", p);    // Outputs "David Hayden"
        Console.WriteLine("{0:f}", p);  // Outputs "David"
        Console.WriteLine("{0:l}", p);  // Outputs "Hayden"
        Console.WriteLine("{0:n}", p);  // Outputs "David Hayden"
        Console.WriteLine("{0:na}", p); // Outputs "David Hayden, Age=99"
        Console.ReadLine();
    }
}

The code is fairly straight forward.  Let's forget about formatProvider for this post and just focus on the switch(format) statement.  The statment essentially just returns a different result based on the value of format.  Format "G" is used by the .NET framework, so just include it for completeness.



Comments

TrackBack said:

# March 8, 2005 8:08 AM

TrackBack said:

# March 8, 2005 8:26 AM

TrackBack said:

# March 9, 2005 6:35 AM

The Mit's Blog said:

# April 10, 2005 5:16 AM
Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

CodeBetter.Com Home