Reference Implementation for IFormattable

二次信任 提交于 2019-12-02 16:24:57
Kevin Cathcart

You seem to misunderstand the design of the .NET Framework's formatting infrastructure. ICustomFormatter should never be referenced inside an implementation of IFormattable.ToString, since that clashes with the intended purpose of that interface.

IFormattable

An object should only implement IFormattable if 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.GetFormat is intended to be a type or interface specific to the class the IFormatProvider was provided to.

For example, the built-in numeric types want to be able to retrieve an instance of System.Globalization.NumberFormatInfo, while the DateTime related classes want to be able to retrieve a System.Globalization.DateTimeFormatInfo.

Implementing IFormattable

So 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 implement IFormattable.

The format parameter

Per the documentation of IFormattable.ToString the 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 formatProvider parameter

If we need anything culture specific, or that would otherwise vary we need to utilize the IFormatProvider parameter. There would be some type that we request from it using IFormatProvider.GetFormat. If the IFormatProvider is null, or if IFormatProvider.GetFormat returns 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 formatProvider is 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 IFormatProvider down. MSDN has an excellent example of implementing IFormattable that shows this very case.

Other ToString overloads

When implementing IFormattable it is important that Object.ToString() be overridden in a manner equivalent to the following

public override string ToString()
{
    return this.ToString(null, System.Globalization.CultureInfo.CurrentCulture);
}

Doing so ensures that somestring + yourobject is equivalent to string.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 the IFormatProvider, you may also want to provide public string ToString(IFormatProvider provider).

ICustomFormatter

So 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 IFormatProvider that can provide the ICustomFormatter type can be passed as the IFormatProvider parameter in methods like string.Format and StringBuilder.AppendFormat.

The provided ICustomFormatter has its Format method called for each formatting that string.Format does. If the ICustomFormatter is unfamiliar with the format string used or has no support for that type it simply delegates to IFormattable.ToString or Object.ToString. The ICustomFormatter documentation 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 existing IFormattable. 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.

For such questions a good source of information can be found inside Mono source code. You'll likely find quite a few uses of this inside its mscorlib.dll code.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!