C#:IFormattable,IFormatProvider和ICustomFormatter之间的连接,以及何时使用什么

时间:2009-11-08 18:38:45

标签: c# formatting

IFormattableIFormatProviderICustomFormatter之间的区别和联系是什么?它们何时会被使用?一个简单的实现示例也非常好。

我并不是故意在.net框架中使用它,但是当我自己实现这些时,在这种情况下,哪些类通常会实现什么接口以及如何正确地执行它。

3 个答案:

答案 0 :(得分:37)

  • IFormattable是支持string.Format格式的对象,即xxx中的{0:xxx}。如果对象支持该接口,string.Format将委托给对象的IFormattable.ToString方法。

  • IFormatProvider是格式化程序用于特定于文化的日期和货币布局等配置信息的来源。

  • 但是,对于像DateTime,您要格式化的实例已经实现IFormattable但您无法控制实现(BCL中提供DateTime,您无法轻松替换它),那里是一种阻止string.Format简单地使用IFormattable.ToString的机制。相反,您实施IFormatProvider,当被要求进行ICustomFormatter实施时,请返回一个。在string.Format委托给对象的ICustomFormatter之前,IFormattable.Format会检查提供商是否IFormatProvider,这反过来可能会向CultureInfo询问特定于文化的数据,例如string.Format

这是一个程序,显示IFormatProvider询问using System; using System.Globalization; class MyCustomObject : IFormattable { public string ToString(string format, IFormatProvider provider) { Console.WriteLine("ToString(\"{0}\", provider) called", format); return "arbitrary value"; } } class MyFormatProvider : IFormatProvider { public object GetFormat(Type formatType) { Console.WriteLine("Asked for {0}", formatType); return CultureInfo.CurrentCulture.GetFormat(formatType); } } class App { static void Main() { Console.WriteLine( string.Format(new MyFormatProvider(), "{0:foobar}", new MyCustomObject())); } } 的内容,以及控制流程如何:

Asked for System.ICustomFormatter
ToString("foobar", provider) called
arbitrary value

打印出来:

class MyFormatProvider : IFormatProvider
{
    public object GetFormat(Type formatType)
    {
        Console.WriteLine("Asked for {0}", formatType);
        if (formatType == typeof(ICustomFormatter))
            return new MyCustomFormatter();
        return CultureInfo.CurrentCulture.GetFormat(formatType);
    }
}

class MyCustomFormatter : ICustomFormatter
{
    public string Format(string format, object arg, IFormatProvider provider)
    {
        return string.Format("(format was \"{0}\")", format);
    }
}

如果更改格式提供程序以返回自定义格式化程序,则会接管:

Asked for System.ICustomFormatter
(format was "foobar")

运行时:

{{1}}

答案 1 :(得分:2)

自定义格式的工作基于三个组件之间的协调:

  • Formattable
  • 格式提供程序
  • 格式化程序

formattable 对象是可以通过实现IFormattable接口使用格式提供程序和格式字符串来格式化其数据的实例。基本上,他们将请求格式提供者获取formatter,然后使用格式字符串(这是格式指令来要求formatter格式化其实例)。日期/时间和数字类型是格式表类型的示例。

格式提供程序是实现IFormatProvider接口的类。他们负责根据调用者请求的格式类型返回formatter对象。格式类型可以是格式提供者可以理解的任何类型,而返回的formatter应该是调用者(在大多数情况下为formattable`object)可以用来格式化其数据的任何类型。

格式化程序是负责提供格式化服务的对象。对于日期/时间和数字类型,格式提供者也是formatters,分别是CultureInfoDateTimeFormatInfoNumberFormatInfo

在通过诸如String.FormatConsole.WriteLineStringBuilder.AppendFormat之类的某些方法实现的复合格式中,当将格式提供程序传递给他们时,他们总是向格式提供程序询问{{1 } {}实现formatter接口。这使开发人员可以为这些方法提供各种自定义格式。

答案 2 :(得分:1)

IFormattable是一个支持不同(命名/自定义)格式的对象 - 例如,数字等。通过使用接口,多个代码块可以使用值和格式字符串,这很常见(例如)数据绑定和string.Format

IFormatProvider填补了一些与格式有关的空白 - 尤其是i18n。最常见的是,CultureInfo用作提供者,要么提供特定的本地格式,要么使用不变文化。

据我所知,ICustomFormatter是无关的,并且更多地与序列化(BinaryFormatter)联系在一起。我错了......

IFormattable对象的示例:

IFormattable d = 123.45M;
string s1 = d.ToString("c", CultureInfo.CurrentCulture), // local currency
       s2 = d.ToString("c", CultureInfo.InvariantCulture); // invariant currency