-
IFormattableis an object which supports formats instring.Format, i.e. thexxxin{0:xxx}.string.Formatwill delegate to an object’sIFormattable.ToStringmethod if the object supports the interface. -
IFormatProvideris a source of configuration information that formatters use for things like culture-specific date and currency layout. -
However, for situations like e.g.
DateTime, where the instance you want to format already implementsIFormattableyet you don’t control the implementation (DateTimeis supplied in the BCL, you can’t replace it easily), there is a mechanism to preventstring.Formatfrom simply usingIFormattable.ToString. Instead, you implementIFormatProvider, and when asked for anICustomFormatterimplementation, return one.string.Formatchecks the provider for anICustomFormatterbefore it delegates to the object’sIFormattable.Format, which would in turn likely ask theIFormatProviderfor culture-specific data likeCultureInfo.
Here is a program which shows what string.Format asks the IFormatProvider for, and how the flow of control goes:
using System;
using System.Globalization;
class MyCustomObject : IFormattable
{
public string ToString(string format, IFormatProvider provider)
{
Console.WriteLine("ToString(\"{0}\", provider) called", format);
return "arbitrary value";
}
}
class MyFormatProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
Console.WriteLine("Asked for {0}", formatType);
return CultureInfo.CurrentCulture.GetFormat(formatType);
}
}
class App
{
static void Main()
{
Console.WriteLine(
string.Format(new MyFormatProvider(), "{0:foobar}",
new MyCustomObject()));
}
}
It prints this:
Asked for System.ICustomFormatter
ToString("foobar", provider) called
arbitrary value
If the format provider is changed to return a custom formatter, it takes over:
class MyFormatProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
Console.WriteLine("Asked for {0}", formatType);
if (formatType == typeof(ICustomFormatter))
return new MyCustomFormatter();
return CultureInfo.CurrentCulture.GetFormat(formatType);
}
}
class MyCustomFormatter : ICustomFormatter
{
public string Format(string format, object arg, IFormatProvider provider)
{
return string.Format("(format was \"{0}\")", format);
}
}
When run:
Asked for System.ICustomFormatter
(format was "foobar")