您似乎误解了 .NET Framework 格式化基础结构的设计。 ICustomFormatter 永远不应在 IFormattable.ToString 的实现中引用,因为这与该接口的预期目的相冲突。
IFormattable
一个对象只有在知道如何格式化自己的情况下才应该实现IFormattable(理想情况下,它当然应该将其委托给另一个类,但这里会有故意的耦合)。一个对象可能知道如何以多种不同的方式格式化自己,因此格式字符串允许您在它们之间进行选择。即使这样,仍然可能缺少信息,这些信息因文化而异。因此,有第二个参数可以间接提供此类信息。
传递给IFormatProvider.GetFormat 的类型旨在成为特定于IFormatProvider 提供给的类的类型或接口。
例如,内置数字类型希望能够检索System.Globalization.NumberFormatInfo 的实例,而DateTime 相关类希望能够检索System.Globalization.DateTimeFormatInfo。
实现IFormattable
假设我们正在创建一些新的自格式化类。如果它只知道一种格式化自己的方法,它应该简单地覆盖object.ToString(),仅此而已。如果该类知道不止一种格式化自己的方法,则应实现IFormattable。
format 参数
IFormattable.ToString 的the documentation 的"G" 格式字符串(代表一般格式)必须支持。建议 null 或空格式字符串等价于"G" 格式字符串。确切的含义取决于我们。
formatProvider 参数
如果我们需要任何特定于文化的东西,或者会有所不同,我们需要使用IFormatProvider 参数。我们会使用IFormatProvider.GetFormat 向它请求某种类型。如果 IFormatProvider 为 null,或者如果 IFormatProvider.GetFormat 为我们想要的类型返回 null,我们应该回退到一些默认来源来获取这些变化的信息。
默认源不必是静态的。可以想象,默认来源可能是应用中的用户设置,formatProvider 用于预览选项更改和/或需要固定格式进行序列化时。
格式化也可能涉及格式化某些子对象。在这种情况下,您可能希望将IFormatProvider 向下传递。 MSDN 有一个实现IFormattable 的excellent example 说明了这种情况。
其他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 变得相关的地方。可以提供ICustomFormatter 类型的IFormatProvider 可以在string.Format 和StringBuilder.AppendFormat 等方法中作为IFormatProvider 参数传递。
提供的ICustomFormatter 有其Format 方法,用于string.Format 所做的每种格式设置。如果ICustomFormatter 不熟悉所使用的格式字符串或不支持该类型,它只会委托给IFormattable.ToString 或Object.ToString。 ICustomFormatter documentation 提供了一个列表,其中列出了如果您正在格式化尚未提供格式化支持的对象时所需的内容,以及如果您只想向现有 IFormattable 添加额外格式时所需的内容。它还提供了添加额外格式案例的示例。
参考
This MSDN page 提供了 .NET 格式化系统的一个很好的概述,并提供了指向 MSDN 中几乎所有其他相关页面的链接。这是几乎所有与格式相关的问题的最佳起点。