Practical .NET

Supporting Multiple String Formats from Your Class

Developers (including you) benefit when you provide a string representation of your class. By implementing IFormattable, you can take control of this representation and provide some flexibility. Besides, if you don't provide one, the Microsoft .NET Framework will provide a useless one for you.

When anything in the Microsoft .NET Framework needs a string representation of your object, it calls your class's ToString method. If you add your object to a dropdown list, for example, the dropdown list will call your object's ToString method, inherited from System.Object, to get something the list can display on the screen. By default, the ToString method returns the name of your class inside curly braces: Your Customer class will return {MyNamespace.Customer}. So, if you add 25 Customer classes to a dropdown list, you get a dropdown list that displays {MyNamespace.Customer} 25 times. That's not very useful.

Not surprisingly, most developers override the ToString method so that it returns something that's actually useful. For the Customer object that would probably be the current values of the Id property or the FirstName and LastName properties. But, in something like the Customer object, there are often a variety of outputs that a developer might want from the ToString method. I can easily imagine that I might want the Customer object to identify itself with these combinations of its properties:

  • LastName, FirstName
  • FirstName MiddleInitial LastName
  • LastName, FirstName MiddleInitial
  • Salutation LastName

Developers typically end up cobbling these other combinations together using string concatenation. You can, however, support those options directly by having your object implement the IFormattable interface. If you want, you can even use this feature to provide more complex outputs -- there's no reason your ToString method couldn't hand back an XML version of your Customer object, for example.

Supporting Multiple Formats
The trick here is to have your class implement the IFormattable interface, which creates a ToString method that accepts a formatting code. For my Customer object and the outputs I listed earlier, I might support format strings like these:

  • L, F: LastName, FirstName
  • F M L: FirstName MiddleInitial LastName
  • L, FM: LastName, FirstName MiddleInitial
  • S L: Salutation LastName

The first step is to have your class implement the IFormattable interface:

Public Class Customer
  Implements IFormattable

End Class

That will cause Visual Studio to add a "formattable" version of the ToString method to your class. It looks something like this:

Public Function ToString1(format As String, formatProvider As IFormatProvider) As String Implements IFormattable.ToString

End Function

Now, it's just a matter of putting some code in that method. This example supports one of my formats and can be easily extended to support the rest:

Select Case format
  Case "F M L"
    Return Me.FirstName & " " & Me.MiddleName & " " & Me.LastName
End Select

With this method in place, developers can now use your format strings with your object anywhere that formatting strings are accepted. For example, all of these statements will work with this Customer object:

Dim cust As New Customer With {
                               .FirstName = "Peter",
                               .MiddleName = "Hunter",
                               .LastName = "Vogel"
String.Format("{0:F M L}", cust)
System.Diagnostics.Debug.Print("{0:F M L}", cust)
Console.WriteLine("{0:F M L}", cust)

If you're working with some .NET Framework component that has a Format property, you can now use your format codes in that property to control your class's output.

Covering the Defaults
If you do implement IFormattable, you're expected to handle the format code G (for "general") and the situation where no formatting string is supplied in code like this:

String.Format("{0}", cust) 

Essentially, this means that you need to pick one format to be your "default" format and use that for the G format and null/nothing. This example extends my code to use "LastName, FirstName" as the G/null/Nothing format (it also provides a Case Else to handle unknown format codes):

Select Case format
  Case "F M L"
    Return Me.FirstName & " " & Me.MiddleName & " " & Me.LastName
  Case "L, F", "G", Nothing
    Return Me.LastName & ", " & Me.FirstName
  Case Else
    Throw New FormatException("Unknown format code for Customer object")
End Select

Implementing the code in the IFormattable version of ToString does not, however, relieve you of the burden of overriding ToString itself -- if a developer calls the default ToString method directly, it will still hand back {MyNamespace.Customer}. The simplest way to handle this is still to override the default ToString method, but, within the method, call your IFormattable ToString method passing one of your format codes.

To call your IFormattable ToString method, you need to provide a value for the second parameter required by the IFormattable ToString method. That second parameter must be a FormatProvider class that handles formatting for the local culture (more technically, some class that implements the IFormatProvider interface). Fortunately, there are a number of places where you can get a FormatProvider (including System.Globalization.CultureInfor.CurrentCulture). Here, I'm passing the CurrentCulture property associated with the thread on which the code is executing:

Public Overrides Function ToString() As String
  Return Me.ToString1("G", Threading.Thread.CurrentThread.CurrentCulture)
End Function

Now, when developers use your class they won't have to concatenate properties together to display your object in a UI. Furthermore, you'll have control over all the acceptable representations of your object. I do like being in control.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at

comments powered by Disqus


  • What's New in Visual Studio 2019 v16.5 Preview 2

    The second preview of Visual Studio 2019 v16.5 has arrived with improvements across the flagship IDE, including the core experience and different development areas such as C++, Python, web, mobile and so on.

  • C# Shows Strong in Tech Skills Reports

    Microsoft's C# programming language continues to show strong in tech industry skills reports, with the most recent examples coming from a skills testing company and a training company.

  • Color Shards

    Sharing Data and Splitting Components in Blazor

    ASP.NET Core Version 3.1 has at least two major changes that you'll want to take advantage of. Well, Peter thinks you will. Depending on your background, your response to one of them may be a resounding “meh.”

  • Architecture Small Graphic

    Microsoft Ships Preview SDK, Guidance for New Dual-Screen Mobile Era

    Microsoft announced a new SDK and developer guidance for dealing with the new dual-screen mobile era, ushered in by the advent of ultra-portable devices such as the Surface Duo.

  • How to Create a Machine Learning Decision Tree Classifier Using C#

    After earlier explaining how to compute disorder and split data in his exploration of machine learning decision tree classifiers, resident data scientist Dr. James McCaffrey of Microsoft Research now shows how to use the splitting and disorder code to create a working decision tree classifier.

.NET Insight

Sign up for our newsletter.

Terms and Privacy Policy consent

I agree to this site's Privacy Policy.

Upcoming Events