IFormattable的参考实现

13

有没有一个好的参考实现可以用于 IFormattable?我计划为我的对象至少创建一个自定义的 IFormatProvider,并且我想确保对 IFormattable.ToString(string, IFormatProvider) 传递的不同可能的参数集进行正确的连接。

目前我拥有的内容:

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);
    }
}

但似乎还有其他潜在的情况需要处理,例如:

  1. 如果formatProvider为null,我应该退回到this.ToString()吗?
  2. 如果formatProvider.GetFormat(typeof(ICustomFormatter))返回null,是否应该抛出特定的异常?

欢迎提供任何博客文章/代码示例/MSDN参考。

2个回答

44
你似乎误解了.NET Framework的格式化基础架构设计。在实现时,永远不应该引用,因为这会与该接口的预期目的发生冲突。 只有当对象知道如何格式化自己时,它才应该实现(理想情况下,它应该将其委托给另一个类,但这里存在故意的耦合)。一个对象可能知道如何以多种不同的方式格式化自己,因此格式字符串允许您在它们之间进行选择。即使是这样,仍然可能缺少信息,如各种文化差异。因此,第二个参数提供了间接的信息。
传递给的类型旨在成为特定于提供的类的类型或接口。
例如,内置的数字类型希望能够检索的实例,而与< DateTime >相关的类希望能够检索。
实现

让我们想象一下,我们正在创建一些新的自我格式化类。如果它只知道一种格式化方法,那么它应该简单地重写object.ToString(),仅此而已。如果这个类知道多种格式化方法,那么它应该实现IFormattable接口。

format参数

根据IFormattable.ToString文档"G"(表示通用格式)的格式字符串必须被支持。建议将null或空格式字符串视为等同于"G"格式字符串。否则确切的含义由我们决定。

formatProvider参数

如果我们需要任何与文化相关的东西,或者其他可能会变化的信息,我们需要利用IFormatProvider参数。我们会使用IFormatProvider.GetFormat从中请求某些类型。如果IFormatProvider为空,或者如果IFormatProvider.GetFormat对于我们想要的类型返回null,我们应该回退到某个默认来源以获取这些变化的信息。

默认的源不一定是静态的。可以想象,默认源可能是应用程序中的用户设置,而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发挥作用的地方。可以将能够提供ICustomFormatter类型的IFormatProvider作为参数传递给string.FormatStringBuilder.AppendFormat等方法。
提供的ICustomFormatter会在每次调用string.Format时调用其Format方法。如果ICustomFormatter对使用的格式字符串不熟悉或不支持该类型,则简单地委托给IFormattable.ToStringObject.ToStringICustomFormatter文档提供了一个列表,如果您要格式化尚未提供格式支持的对象,需要做什么,以及如果您仅想为现有的IFormattable添加额外格式,需要做什么。它还提供了一个添加额外格式的示例。

参考

此MSDN页面提供了.NET格式化系统的很好的概述,并提供了与MSDN中几乎所有其他相关页面的链接。对于几乎任何格式化相关问题,这都是最好的起点。


2
感谢您提供详细的答案和参考资料! - Scott Wegner
2
当我第一次看到这个问题时,我基本上和你一样困惑,所以我查看了反编译器中的框架,并开始阅读MSDN页面,但我只是更加困惑了。在我阅读了大部分的MSDN页面之后,我才找到了主要的参考页面。即使如此,它也花费了一段时间才开始理解。有一些棘手的部分。例如,我怀疑ICustomFormatterIFormatProvider一起使用的唯一原因是它是1.0框架的后期添加,他们不想添加一个新的string.Format重载。 - Kevin Cathcart

1

对于这样的问题,可以在Mono源代码中找到很好的信息来源。你可能会在mscorlib.dll代码中找到它的许多用途。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接