String.Format - 它是如何工作的以及如何实现自定义格式字符串

81

使用String.Format(),可以以多种不同的方式格式化例如DateTime对象。每次我需要查找所需的格式时,都需要在互联网上搜索。几乎总能找到我可以使用的示例。例如:

String.Format("{0:MM/dd/yyyy}", DateTime.Now);          // "09/05/2012"

我不知道它是如何工作以及哪些类支持这些“神奇”的附加字符串。

所以我的问题是:

  1. String.Format 如何将附加信息 MM/dd/yyyy 映射到字符串结果?
  2. 所有 Microsoft 对象都支持这个功能吗?
    这个功能是否有文档说明?
  3. 是否可能做到这样:
    String.Format("{0:MyCustomFormat}", new MyOwnClass())

你可以看一下这个链接:http://www.codeproject.com/Articles/6533/Custom-String-Formatting-in-NET - V4Vendetta
7个回答

90

String.Format将字符串中每个标记(如{0}等)与相应的对象进行匹配:https://learn.microsoft.com/en-us/dotnet/api/system.string.format#overloads

还可以提供格式化字符串:

{index [,alignment][:formatString]}

如果提供了formatString,则相应的对象必须实现IFormattable接口,并具有接受formatString并返回相应格式化字符串的ToString方法:https://learn.microsoft.com/en-us/dotnet/api/system.iformattable.tostring

还可以使用IFormatProvider来捕获基本的格式化标准/默认值等。 示例在此在此.

因此,按顺序回答您的问题:

  1. 它在DateTime对象上使用IFormattable接口的ToString()方法,并传递MM/dd/yyyy格式字符串。正是该实现返回了正确的字符串。

  2. 任何实现IFormattable的对象都支持此功能。您甚至可以编写自己的对象!

  3. 是的,请参见上文。


11
+1 是为了链接到“文档”。在互联网上搜索可能是可以的。但当您需要更深入的理解时,您应该阅读手册。 - MarkJ
很好的回答,但你能告诉我在哪里可以找到每个实现IFormattable接口的类所允许的格式字符串吗?例如,DateTime支持(从我的记忆中)y M d h m s等格式。数值类型支持C表示货币,但这是我通过搜索得知的,并非来自Microsoft文档。 - hwcverwe
3
这是关于“格式化类型”的文章,可以在链接中查看。 - Vladimir

20

据我所知,您需要在您的类中实现IFormattable接口来支持此功能。这个接口要求定义ToString方法,该方法接受您传递给String.Format的参数。

以下是一个示例。

// Define other methods and classes here
public class Sample : IFormattable
{
     public string ToString(string format, IFormatProvider provider)
     {
         return String.Concat("Your custom format was ", format);
     }
}

String.Format("{0:MyCustomFormat}", new Sample())

5
  1. 查看官方 MSDN 文档,这里有完整的 DateTime 格式字符串列表: http://msdn.microsoft.com/en-us/library/az4se3k1.aspx。确实有相当多的 "神奇" 字符串。

  2. 据我所知,并非所有类型都有 "有趣" 的格式化,但是所有类型都支持 ToString()。如果您需要格式化内置对象,则可以添加扩展方法来执行此操作,但通常在任何需要的地方(或者换句话说,我只为自己的类型编写了自定义格式化程序)提供了格式化。

  3. 是的,您可以编写自己的格式化程序,如果您有可以以不同方式格式化的数据,则可能应该通过实现 IFormattable 来编写自定义格式化程序,再次参见这里的文档:http://msdn.microsoft.com/en-us/library/system.iformattable.aspx。这很简单,您只需检查所提供的字符串并根据这些编写出您的数据,背后没有任何魔力:-)


4
在底层,String.Format 执行以下操作:
IFormattable formattable = objectToFormat as IFormattable;
if (formattable != null)
{
    formattable.ToString(objectToFormat);
}
else
{
    objectToFormat.ToString();
}

针对您的问题:

  1. String.Format如何将附加信息MM/dd/yyyy映射到字符串结果中?

    如上所述,它只是调用IFormattable.ToString(string format, IFormatProvider provider)方法。提供程序通常可以告诉您系统的文化是什么。由于人们通常不在类似于您的情况下通过String.Format()传递它,因此通常为null。

  2. 所有Microsoft对象是否都支持此功能? 有文档记录吗?

    任何实现IFormattable接口的对象都支持此功能。

  3. 是否可以像这样做:String.Format("{0:MyCustomFormat}, new MyOwnClass())

    如果您想要自己的对象根据提供的格式执行某些操作,则需要实现IFormattable接口。

有大量的支持类和枚举器来确保格式字符串基本相似。更多信息请参阅此处


0

是的,这是可能的 - 它可以完全定制。请查看日期和时间自定义格式的 this

如果您有自己的对象,那么您可以覆盖 ToString() 方法并输出您认为适当的表示形式。一旦您这样做了,您就可以使用 String.Format("{0:MyCustomFormat}", new MyOwnClass()),因为这会隐式调用 MyOwnClass.ToString()


-1 - OP 正在询问关于不仅仅是 DateTime 格式化的问题。只提供一个链接并不是一个答案。 - Oded
1
非常苛刻。DateTime 是其中一个方面,而我正在扩展我的答案时你却给我点了踩。 - Maciej
6
请展开回答并发布,这样您就不会被投下反对票。 - Oded

0
回答你的第三个问题:这种语法不可能实现,但是你可以为未创建的类型提供IFormatProviderICustomFormatter的实例,或者在你的类型内部实现IFormattable(虽然这基本上扩展了ToString)。

0

日期的文档可以在这里找到: http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx

这应该会告诉你所有日期格式字符(如MM)的确切含义。

如果您想更改自定义类的字符串输出方式,可以像这样覆盖ToString方法:

public class User
{
     public string Name { get; set; }
     public int Age { get; set; }

     public override string ToString()
     {
         return this.Name + " is " + this.Age + " years old.";
     }
}

然后你只需要像这样做 myUser.ToString() 就可以得到你指定的输出。


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