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

C#:IFormattable、IFormatProvider和ICustomFormatter之间的连接,以及何时使用什么,c#,formatting,C#,Formatting,IFormattable、IFormatProvider和ICustomFormatter之间的区别和联系是什么,何时使用它们?一个简单的实现示例也很好 我并不是说在.net framework中何时使用它,而是指我自己何时实现这些,在这种情况下,什么类通常实现什么接口以及如何正确实现它。是一个支持不同(命名/自定义)格式的对象,例如,数字等。通过使用接口,多个代码块可以使用值和格式字符串,这在数据绑定和string.format中很常见 A填补了一些关于格式化的空白,特别是i18n。最常见的是

IFormattable
IFormatProvider
ICustomFormatter
之间的区别和联系是什么,何时使用它们?一个简单的实现示例也很好

我并不是说在.net framework中何时使用它,而是指我自己何时实现这些,在这种情况下,什么类通常实现什么接口以及如何正确实现它。

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

A填补了一些关于格式化的空白,特别是i18n。最常见的是,
CultureInfo
用作提供程序,提供特定的本地格式或不变的区域性

据我所知,是不相关的,并且更多地与序列化相关(
BinaryFormatter
)。我可能错了

IFormattable
对象的示例:

IFormattable d = 123.45M;
string s1 = d.ToString("c", CultureInfo.CurrentCulture), // local currency
       s2 = d.ToString("c", CultureInfo.InvariantCulture); // invariant currency
  • IFormattable
    是一个支持
    string.Format
    格式的对象,即
    {0:xxx}
    中的
    xxx
    <如果对象支持该接口,则code>string.Format将委托给对象的
    IFormattable.ToString
    方法

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

  • 但是,对于诸如
    DateTime
    之类的情况,您要格式化的实例已经实现了
    IFormattable
    ,但您无法控制实现(
    DateTime
    在BCL中提供,您无法轻松替换它),有一种机制可以防止
    string.Format
    简单地使用
    IFormattable.ToString
    。相反,您实现了
    IFormatProvider
    ,当要求提供
    ICustomFormatter
    实现时,返回一个
    string.Format
    在委托给对象的
    IFormattable.Format
    之前,检查提供程序是否有
    ICustomFormatter
    ,这反过来可能会向
    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")

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

  • 可格式化
  • 格式提供程序
  • 格式化程序
formattable对象是通过实现
IFormattable
接口,可以使用格式提供程序和格式字符串格式化其数据的实例。基本上,他们会请求格式提供程序获取一个
格式化程序
,然后使用格式字符串(即格式说明)来请求
格式化程序
格式化他们的实例。日期/时间和数字类型是formattable类型的示例

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

格式化程序是负责提供格式化服务的对象。对于日期/时间和数字类型,格式提供程序也是
格式化程序
,它们是
CultureInfo
DateTimeFormatInfo
NumberFormatInfo


在由一些方法(如
String.Format
Console.WriteLine
StringBuilder.AppendFormat
)实现的复合格式中,当向他们传递格式提供程序时,他们总是要求格式提供程序提供实现
ICustomFormatter
接口的
formatter
。这允许开发人员为这些方法提供各种自定义格式

为什么在
MyFormatProvider.GetFormat
中返回
CultureInfo.CurrentCulture.GetFormat
?在
MyCustomFormatter.Format
中,您将如何使用
IFormatProvider
?默认的格式提供程序是CultureInfo.CurrentCulture;如果在
string.Format
的某个重载中未指定一个,则将使用该函数。我已经解释了您使用IFormatProvider的目的-提供配置信息(例如,询问CultureInfo)以及日期格式(例如,使用CultureInfo.DateTimeFormat)。不要在GetFormat中使用
return CultureInfo.CurrentCulture.GetFormat(formatType)
,否则它会中断。最终它将被转换到ICustomFormatter中。请参阅:@Wouter每次使用
CultureInfo.CurrentCulture
作为
IFormatProvider
时,它都会调用
GetFormat
。如果出现这种情况,那就是
CultureInfo
实例的问题,因为它实现了
IFormatProvider
。是否有您发现问题的特定实现?请参阅:和,了解如果要打印具有当前区域性的小数(例如,分隔符的逗号与点与小数),代码路径将如何期望
IFormatProvider
(通常是
CultureInfo
)支持
GetFormat
)。如果之前没有为
ICustomFormatter
调用
GetFormat
,则无法提供
CultureInfo
。这是一个非常复杂的问题