Customizing Format StringsĀ 

The .NET Framework supports extending its built-in formatting mechanism so you can create your own ToString method that accepts user-defined format strings, or create a format provider that invokes your own Format method to perform custom formatting of a type. You create your own ToString method by implementing the IFormattable interface, and your own Format method by implementing the ICustomFormatter and IFormatProvider interfaces.

The information in this section is limited to adding custom format strings to user-defined types and existing base types, but the principles described can be applied to any type.

Adding Custom Format Strings for Custom Types

If you create your own custom type, you can add support for processing your own custom format strings by implementing the IFormattable interface and that interface's ToString method. This means you can control what format strings are recognized by your custom type. The benefit of implementing the IFormattable interface instead of merely adding a ToString method to your custom type is that you can guarantee users of your ToString method a predefined calling syntax and return type.

The ToString method of the IFormattable interface takes a format string parameter and a format provider parameter. If the format string parameter is an empty string or null (Nothing in Visual Basic), perform default formatting. If the format provider is null, use a default format provider.

If a custom format string is passed to your custom version of ToString, perform the appropriate formatting; otherwise, call a suitable .NET Framework method to perform standard formatting.

In the following example, the MyType custom type implements the IFormattable interface. If you create a new instance of the MyType class, and pass the "b" custom format string to the instance's ToString method, an overload of Convert.ToString returns the binary (base 2) string representation of the value of the instance. If "b" is not passed, the value of the instance is formatted by its own ToString method; that is, integer myValue is formatted by the System.Int32.ToString method.

Public Class MyType
    Implements IFormattable
    ' Assign a value for the class.
    Private myValue As Integer    
    
    ' Add a constructor.
    Public Sub New(value As Integer)
        myValue = value
    End Sub
    
    ' Write a custom Format method for the type.
    Public Overloads Function ToString(format As String, fp As IFormatProvider) As String _
    Implements IFormattable.ToString
    
        If format.Equals("b") Then
            Return Convert.ToString(myValue, 2)
        Else
            Return myValue.ToString(format, fp)
        End If
    End Function
End Class
public class MyType : IFormattable
{
    // Assign a value for the class.
    private int myValue;
    
    // Add a constructor.
    public MyType( int value )
    {
        myValue = value;
    }
    // Write a custom Format method for the type.
    public string ToString(string format, IFormatProvider fp)
    {
        if (format.Equals ("b"))
            {
            return Convert.ToString (myValue, 2);
            }
        else
            {
            return myValue.ToString(format, fp);
            }
    }
}

The following example demonstrates how the MyType class and "b" format string are used.

Dim mtype As New MyType(42)
Dim MyString As String = mtype.ToString("b", null)
Dim YourString As String = mtype.ToString("p", null)
' MyString has the value: "101010".
' YourString has the value: "42 %".
MyType mtype = new MyType(42);
String MyString = mtype.ToString("b", null);
String YourString = mtype.ToString("p", null);
// MyString has the value: "101010".
// YourString has the value: "42 %".

Adding Custom Format Strings to Existing Types

You can control how an existing base type is formatted, and provide additional codes for formatting, by creating a format provider class that implements ICustomFormatter and IFormatProvider.

When you pass a format provider to the ToString method of a base type, the base type uses the passed format provider to define its formatting rules rather than the default format provider. To create a custom format provider, you should do the following:

  1. Define a class that implements the two previously mentioned interfaces and overrides GetFormat and Format.

  2. Pass that class into a method (like String.Format) that takes the IFormatProvider as a parameter. Doing so causes String.Format to recognize the custom format scheme defined in the new format provider class.

The following example defines a class that adds a custom Format method that can produce different base values of an integer.

Public Class MyFormat
    Implements IFormatProvider
    Implements ICustomFormatter
    
    ' String.Format calls this method to get an instance of an
    ' ICustomFormatter to handle the formatting.
    Public Function GetFormat(service As Type) As Object _
    Implements IFormatProvider.GetFormat
    
        If service.ToString() = GetType(ICustomFormatter).ToString() Then
            Return Me
        Else
            Return Nothing
        End If
    End Function
    
    ' After String.Format gets the ICustomFormatter, it calls this format
    ' method on each argument.
    Public Function Format(theformat As String, arg As Object, provider As IFormatProvider) As String _
    Implements ICustomFormatter.Format
    
        If theformat Is Nothing Then
            Return String.Format("{0}", arg)
        End If
        Dim i As Integer = theformat.Length
            ' If the object to be formatted supports the IFormattable
            ' interface, pass the format specifier to the 
            ' objects ToString method for formatting.
        If Not theformat.StartsWith("B") Then
            ' If the object to be formatted supports the IFormattable
            ' interface, pass the format specifier to the 
            ' objects ToString method for formatting.
            If TypeOf arg Is IFormattable Then
                return CType(arg, IFormattable).ToString(format, provider)
            End If
            ' If the object does not support IFormattable, 
            ' call the objects ToString method with no additional
            ' formatting. 
            ElseIf (arg Is Nothing) Then
                return arg.ToString()
            End If
        End If
        ' Uses the format string to
        ' form the output string.
        theformat = theformat.Trim(New Char() {"B"c})
        Dim b As Integer = Convert.ToInt32(theformat)
        Return Convert.ToString(CInt(arg), b)
    End Function
End Class
public class MyFormat : IFormatProvider, ICustomFormatter
{
    // String.Format calls this method to get an instance of an
    // ICustomFormatter to handle the formatting.
    public object GetFormat (Type service)
    {
        if (service == typeof (ICustomFormatter))
        {
            return this;
        }
        else
        {
            return null;
        }
    }
    // After String.Format gets the ICustomFormatter, it calls this format
    // method on each argument.
    public string Format (string format, object arg, IFormatProvider provider) 
    {
        if (format == null)
        {
            return String.Format ("{0}", arg);
        }
        // If the format is not a defined custom code,
        // use the formatting support in ToString.
        if (!format.StartsWith("B")) 
        {
            //If the object to be formatted supports the IFormattable
            //interface, pass the format specifier to the 
            //objects ToString method for formatting.
            if (arg is IFormattable) 
            {
                return ((IFormattable)arg).ToString(format, provider);
            } 
            //If the object does not support IFormattable, 
            //call the objects ToString method with no additional
            //formatting. 
            else if (arg != null) 
            {
                return arg.ToString();
            }
        }
        // Uses the format string to
        // form the output string.
        format = format.Trim (new char [] {'B'});
        int b = Convert.ToInt32 (format);
        return Convert.ToString ((int)arg, b);
    }
}

In the following example, the String.Format method uses the custom Format method defined in MyFormat to display the base 16 representation of MyInt.

Dim MyInt As Integer = 42
Dim MyString As String = String.Format (New MyFormat (), "{0} in the custom B16 format is {1:B16}", New Object () { MyInt, MyInt } )
' MyString has the value: "42 in custom B16 format is 2a".
int MyInt = 42;
string MyString = String.Format (new MyFormat (), "{0} in the custom B16 format is {1:B16}", new object [] { MyInt, MyInt } );
// MyString has the value: "42 in custom B16 format is 2a".

See Also

Reference

IFormattable Interface
IFormatProvider
ICustomFormatter

Other Resources

Formatting Types