您似乎误解了 .NET Framework 格式化基础结构的设计。ICustomFormatter
永远不应在 的实现中引用IFormattable.ToString
,因为这与该接口的预期目的相冲突。
IFormattable
一个对象只有IFormattable
在知道如何格式化自己的情况下才应该实现(理想情况下,它当然应该将其委托给另一个类,但这里会有故意的耦合)。一个对象可能知道如何以多种不同的方式格式化自己,因此格式字符串允许您在它们之间进行选择。即使这样,仍然可能缺少信息,这些信息因文化而异。因此,有第二个参数可以间接提供此类信息。
传递给的类型IFormatProvider.GetFormat
旨在成为特定IFormatProvider
于提供给的类的类型或接口。
例如,内置数字类型希望能够检索 的实例System.Globalization.NumberFormatInfo
,而DateTime
相关类希望能够检索System.Globalization.DateTimeFormatInfo
.
实施IFormattable
所以让我们想象我们正在创建一些新的自格式化类。如果它只知道一种格式化自己的方法,它应该简单地覆盖object.ToString()
,仅此而已。如果该类知道不止一种格式化自身的方法,则应该实现IFormattable
.
format
参数_
根据格式字符串(代表通用格式)的文档,必须支持。建议 null 或空格式字符串等效于. 确切的含义取决于我们。IFormattable.ToString
"G"
"G"
formatProvider
参数_
如果我们需要任何特定于文化的东西,或者会有所不同,我们需要使用该IFormatProvider
参数。我们会使用IFormatProvider.GetFormat
. 如果IFormatProvider
为空,或者如果IFormatProvider.GetFormat
我们想要的类型返回空,我们应该回退到这个变化信息的一些默认源。
默认源不必是静态的。可以想象,默认来源可能是应用程序中的用户设置,并且formatProvider
用于预览选项更改和/或序列化需要固定格式时。
格式化也可能涉及格式化某些子对象。在这种情况下,您可能想要传递IFormatProvider
下去。MSDN 有一个很好的实现示例IFormattable
,说明了这种情况。
其他ToString
重载
在实现时,以等同于以下方式的方式被覆盖IFormattable
是很重要的Object.ToString()
public override string ToString()
{
return this.ToString(null, System.Globalization.CultureInfo.CurrentCulture);
}
这样做可以确保它somestring + yourobject
等同于string.Format("{0}{1}",somestring, yourobject)
,您的用户期望它是正确的。
为了方便您的用户,您可能应该提供string ToString(string format)
. 此外,如果您的默认格式有任何可以从中受益的不同组件IFormatProvider
,您可能还需要提供public string ToString(IFormatProvider provider)
.
ICustomFormatter
那么如果我们想格式化一个不知道如何格式化自己的类,或者我们想使用一些类本身不支持的格式,我们该怎么办。这就是 ICustomFormatter 变得相关的地方。可以IFormatProvider
提供ICustomFormatter
类型的 可以作为 和 等方法中的参数IFormatProvider
传递。string.Format
StringBuilder.AppendFormat
提供的每个格式都调用了ICustomFormatter
它的方法。如果不熟悉使用的格式字符串或不支持该类型,则它只是委托给or 。如果您正在格式化尚未提供格式化支持的对象,该文档提供了所需内容的列表,以及如果您只想向现有的. 它还提供了添加额外格式案例的示例。Format
string.Format
ICustomFormatter
IFormattable.ToString
Object.ToString
ICustomFormatter
IFormattable
参考
这个 MSDN 页面提供了 .NET 格式化系统的一个很好的概述,并提供了指向 MSDN 中几乎所有其他相关页面的链接。这是几乎所有与格式相关的问题的最佳起点。