2013-01-08 45 views
11

IFormattable是否有很好的参考实现?我计划至少为我的对象定制一个自定义IFormatProvider,并且我要确保接线对于传递给IFormattable.ToString(string, IFormatProvider)的不同可能参数集合是正确的。IFormattable的参考实现

我到目前为止有:

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参考表示赞赏。

回答

35

您似乎误解了.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为空,或者IFormatProvider.GetFormat对于我们想要的类型返回null,我们应该回退到某些默认源以获取此不同信息。

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

也有可能格式化可能涉及格式化一些子对象。在这种情况下,您可能想要通过IFormatProvider。 MSDN有一个excellent example实施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的方法中作为IFormatProvider参数传递。

提供的ICustomFormatterstring.Format所做的每种格式都要求其Format方法。如果ICustomFormatter不熟悉所使用的格式字符串或不支持该类型,那么它只是代表IFormattable.ToStringObject.ToString。如果您格式化尚未提供格式支持的对象,则ICustomFormatter documentation提供了所需内容的列表,如果您只想向现有的IFormattable添加额外格式,则需要什么。它还提供了添加额外格式大小写的例子。

参考

This MSDN page提供了.NET格式化系统的一个很好的概述,并提供链接到MSDN几乎所有的其他相关网页。这是几乎所有与格式相关的问题开始的最佳位置。

+2

感谢您的详细解答和参考! –

+2

当我第一次看到这个问题时,我基本上和以前一样对所有这些都感到困惑,所以我看着反射器的框架,开始阅读MSDN页面,而我只是更加困惑。在我找到主要参考页面之前,我已经阅读了大部分MSDN页面。即使如此,它开始点击之前花了一段时间。有一些棘手的部分。例如,我怀疑'ICustomFormatter'与IFormatProvider一起使用的唯一原因是因为它是1.0框架的一个晚期附加,并且他们不想添加新的'string.Format'重载。 –

0

对于这样的问题好的来源的信息可以在Mono的源代码里找到。您可能会在其mscorlib.dll代码中发现其中不少用处。