Geeks With Blogs
Tom Fischer

ToString() and the underestimated IFormattable

Everyone knows you always should override the ToString() function on you custom objects. But most programmers (including me until yesterday) leave it there.

I ran into a problem these days where I wanted a specific xml representation and a tap separated representation of the same custom object. The "experienced" programmer would just write their own format function. But it felt more old fashion and not quite OO like.

And then I read the Tip 5 in the book Effective C# programming - and it change my life again (there is lot's of life changing going on :-)

I totally agree with Scott Meyers about IFormattable but I have a slightly different approach for implementing, which makes it even easier to read (at least from my perspective)

So what is IFormattable? IFormatProvider? ICustomFormatter?  Why are there so many?

The quick answer is: Don't worry about IFormatProvider or ICustomFormatter for most of your stuff.

Implementing IFormatProvider via the pattern described below is all you will need...  usually!

When you implement IFormattable you have to implement one function (hurray that's it):

public string ToString(string format, IFormatProvider formatProvider)
You can use
- either only the first string parameter  (then you have access to all your private/protected members)
- or pass you own implementation of how you want to have it formatted. (Then you only have public members available)

I personally think for most of the cases the first option is easier and good enough. But it was fun yesterday to play around with the implementation of IFormattable. First it was not straight forward but after getting to know it (especially realizing the pattern the .NET team chose to use)- it is pretty cool (Ended up being a Factory Pattern)

Here is the code for a simple class which implements IFormattable.

public class TomType : IFormattable
{
public virtual string Name { get; set; }
public string First { get; set; }

public string ToString(string format, IFormatProvider formatProvider)
{
if (formatProvider != null)
{
ICustomFormatter fmt = formatProvider.GetFormat(
this.GetType()) as ICustomFormatter;
if (fmt != null) { return fmt.Format(format, this, formatProvider); }
}
switch (format)
{
case "a": return First + ", " + Name;
case "first": return First;
case "G": default: return Name;
}
} }

Note: First we check if the consumer wants to use a custom formater or if we just want to use our internal formating option. Simple but very effective.

The case statement is the actual place where all the "magic" happens.
Note: Make sure that there is always an implementation for G. In my case I use the default in the switch, so I could have skipped it.

This already solved my problem with the two ToString() Implementations I needed: plain and xml

But let's look at the more fancy way and see how a custom Formatter works.

The implementation of  IFormatPorvider is like the name says a provider aka "Factory Pattern". You choose the actual Formatter (worker) class, depending on the calling Type. In our case the implementation of IFormatProvider checks for our Type (TomType) and returns an instance (a "Singleton Pattern" could also be instead) of the actual implementation: TomsCustomFormatter:

public class CustomFormatProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(TomType))
{
return new TomsCustomFormater();
}
return null;
}
}

public class TomsCustomFormater : ICustomFormatter
{
public string Format(string format, object arg, IFormatProvider formatProvider)
{
TomType t = arg
as TomType;
if (t == null) { return arg.ToString(); }
return "TomsCustomFormater: " + t.First + ", " + t.Name;
}
}

If we run a little demo now:

static void Main(string[] args)
{
TomType t =
new TomType() { Name = "Fischer", First = "Tom" };

Console.WriteLine(t.ToString(
"a", null));
Console.WriteLine(t.ToString(
"first", null));
Console.WriteLine(t.ToString(
null, new CustomFormatProvider()));
}

We will get the expected result:

Tom, Fischer
Tom
TomsCustomFormater: Tom, Fischer

That's it. I hope you enjoyed this as much as I did it when I stumbled over it

Tom

Posted on Friday, August 29, 2008 10:30 AM C# , .NET Framework | Back to top


Comments on this post: ToString() and the underestimated IFormattable ( IFormatPorvider, ICustomFormatter) - Why to use it!

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © ftom | Powered by: GeeksWithBlogs.net