Is there a good reference implementation for IFormattable? I plan to have at least one custom IFormatProvider for my object, and I want to make sure that the wiring is correct for the different possible parameter sets passed to IFormattable.ToString(string, IFormatProvider).
What I have so far:
public class MyDataClass : IFormattable
{
/// <seealso cref="IFormattable.ToString(string, IFormatProvider)"/>
public string ToString(string format, IFormatProvider formatProvider)
{
ICustomFormatter formatter = (ICustomFormatter)formatProvider.GetFormat(typeof(ICustomFormatter));
return formatter.Format(format, this, formatProvider);
}
}
But it seems like there are other potential situations that should be covered, i.e.:
- If
formatProvideris null, should I fall back tothis.ToString()? - If
formatProvider.GetFormat(typeof(ICustomFormatter))returnsnull, is there a particular exception I should throw?
Any blog posts / code samples / MSDN references are appreciated.
You seem to misunderstand the design of the .NET Framework's formatting infrastructure.
ICustomFormattershould never be referenced inside an implementation ofIFormattable.ToString, since that clashes with the intended purpose of that interface.IFormattableAn object should only implement
IFormattableif it knows how to format itself (ideally it should delegate that to another class of course, but there would be deliberate coupling here). An object may know how to format itself multiple different ways, so the format string allows you to pick between them. Even with that there may still be missing information, such things that vary by culture. Therefore there is a second parameter that provides such information indirectly.The type passed to
IFormatProvider.GetFormatis intended to be a type or interface specific to the class theIFormatProviderwas provided to.For example, the built-in numeric types want to be able to retrieve an instance of
System.Globalization.NumberFormatInfo, while theDateTimerelated classes want to be able to retrieve aSystem.Globalization.DateTimeFormatInfo.Implementing
IFormattableSo let's imagine we are creating some new self-formatting class. If it knows only one way to format itself, it should simply override
object.ToString(), and nothing more. If the class knows more than one way to format itself should implementIFormattable.The
formatparameterPer the documentation of
IFormattable.ToStringthe format string of"G"(which represents the general format) must be supported. It is recommended that a null or empty format string be equivalent to a format string of"G". The exact meaning is otherwise up to us.The
formatProviderparameterIf we need anything culture specific, or that would otherwise vary we need to utilize the
IFormatProviderparameter. There would be some type that we request from it usingIFormatProvider.GetFormat. If theIFormatProvideris null, or ifIFormatProvider.GetFormatreturns null for the type we want we should fall back to some default source for this varying information.The default source need not be static. It is conceivable that the default source might be a user setting in the app, and the
formatProvideris used to preview option changes and/or when a fixed format is needed for serialization.It is also possible that formatting may involve formatting some sub-object. In that case you probably want to pass the
IFormatProviderdown. MSDN has an excellent example of implementingIFormattablethat shows this very case.Other
ToStringoverloadsWhen implementing
IFormattableit is important thatObject.ToString()be overridden in a manner equivalent to the followingDoing so ensures that
somestring + yourobjectis equivalent tostring.Format("{0}{1}",somestring, yourobject), which your users will expect to be true.For the convenience of your users, you should probably provide
string ToString(string format). Also if your default format has any varying components that can benefit from theIFormatProvider, you may also want to providepublic string ToString(IFormatProvider provider).ICustomFormatterSo what do we do if we want to format a class that does not know how to format itself, or we want to use some format not supported by the class itself. That is where ICustomFormatter becomes relevant. An
IFormatProviderthat can provide theICustomFormattertype can be passed as theIFormatProviderparameter in methods likestring.FormatandStringBuilder.AppendFormat.The provided
ICustomFormatterhas itsFormatmethod called for each formatting thatstring.Formatdoes. If theICustomFormatteris unfamiliar with the format string used or has no support for that type it simply delegates toIFormattable.ToStringorObject.ToString. TheICustomFormatterdocumentation provides a list of what is needed if you are formatting an object that does not already provide formatting support, and what is needed if you merely want to add an extra format to an existingIFormattable. It also provides an example of the adding an extra format case.Reference
This MSDN page provides a great overview of the .NET formatting system, and provides links to pretty much all the other relevant pages in MSDN. It is the best place to start for almost any formatting related question.