【问题标题】:Reference Implementation for IFormattableIFormattable 的参考实现
【发布时间】:2012-12-22 16:27:50
【问题描述】:

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 为空,我应该回退到this.ToString()吗?
  2. 如果formatProvider.GetFormat(typeof(ICustomFormatter)) 返回null,我应该抛出一个特定的异常吗?

感谢任何博客文章/代码示例/MSDN 参考。

【问题讨论】:

    标签: c# .net iformattable


    【解决方案1】:

    您似乎误解了 .NET Framework 格式化基础结构的设计。 ICustomFormatter 永远不应在 IFormattable.ToString 的实现中引用,因为这与该接口的预期目的相冲突。

    IFormattable

    一个对象只有在知道如何格式化自己的情况下才应该实现IFormattable(理想情况下,它当然应该将其委托给另一个类,但这里会有故意的耦合)。一个对象可能知道如何以多种不同的方式格式化自己,因此格式字符串允许您在它们之间进行选择。即使这样,仍然可能缺少信息,这些信息因文化而异。因此,有第二个参数可以间接提供此类信息。

    传递给IFormatProvider.GetFormat 的类型旨在成为特定于IFormatProvider 提供给的类的类型或接口。

    例如,内置数字类型希望能够检索System.Globalization.NumberFormatInfo 的实例,而DateTime 相关类希望能够检索System.Globalization.DateTimeFormatInfo

    实现IFormattable

    假设我们正在创建一些新的自格式化类。如果它只知道一种格式化自己的方法,它应该简单地覆盖object.ToString(),仅此而已。如果该类知道不止一种格式化自己的方法,则应实现IFormattable

    format 参数

    IFormattable.ToStringthe documentation"G" 格式字符串(代表一般格式)必须支持。建议 null 或空格式字符串等价于"G" 格式字符串。确切的含义取决于我们。

    formatProvider 参数

    如果我们需要任何特定于文化的东西,或者会有所不同,我们需要使用IFormatProvider 参数。我们会使用IFormatProvider.GetFormat 向它请求某种类型。如果 IFormatProvider 为 null,或者如果 IFormatProvider.GetFormat 为我们想要的类型返回 null,我们应该回退到一些默认来源来获取这些变化的信息。

    默认源不必是静态的。可以想象,默认来源可能是应用中的用户设置,formatProvider 用于预览选项更改和/或需要固定格式进行序列化时。

    格式化也可能涉及格式化某些子对象。在这种情况下,您可能希望将IFormatProvider 向下传递。 MSDN 有一个实现IFormattableexcellent 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.FormatStringBuilder.AppendFormat 等方法中作为IFormatProvider 参数传递。

    提供的ICustomFormatter 有其Format 方法,用于string.Format 所做的每种格式设置。如果ICustomFormatter 不熟悉所使用的格式字符串或不支持该类型,它只会委托给IFormattable.ToStringObject.ToStringICustomFormatter documentation 提供了一个列表,其中列出了如果您正在格式化尚未提供格式化支持的对象时所需的内容,以及如果您只想向现有 IFormattable 添加额外格式时所需的内容。它还提供了添加额外格式案例的示例。

    参考

    This MSDN page 提供了 .NET 格式化系统的一个很好的概述,并提供了指向 MSDN 中几乎所有其他相关页面的链接。这是几乎所有与格式相关的问题的最佳起点。

    【讨论】:

    • 感谢您的详细解答和参考!
    • 当我第一次看到这个问题时,我基本上和你一样对这一切感到困惑,所以我在反射器中查看了框架,并开始阅读 MSDN 页面,我只是更加困惑。在我找到主要参考页面之前,我一直阅读了大部分 MSDN 页面。即使那样,它也花了一段时间才开始点击。有一些棘手的部分。例如,我怀疑 ICustomFormatter 与 IFormatProvider 一起使用的唯一原因是因为它是 1.0 框架的后期添加,并且他们不想添加新的 string.Format 重载。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-09
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多