复合格式设置Composite Formatting

.NET 复合格式设置功能使用对象列表和复合格式字符串作为输入。The .NET composite formatting feature takes a list of objects and a composite format string as input. 复合格式字符串由固定文本和索引占位符混和组成,其中索引占位符称为格式项,对应于列表中的对象。A composite format string consists of fixed text intermixed with indexed placeholders, called format items, that correspond to the objects in the list. 格式设置操作产生的结果字符串由原始固定文本和列表中对象的字符串表示形式混和组成。The formatting operation yields a result string that consists of the original fixed text intermixed with the string representation of the objects in the list.

重要

相较使用复合格式字符串,如果正在使用的语言和语言版本支持,则可使用内插字符串Instead of using composite format strings, you can use interpolated strings if the language and language version that you're using support them. 内插字符串是包含内插表达式的字符串 。An interpolated string is a string that contains interpolated expressions. 每个内插表达式都使用表达式的值进行解析,并在分配字符串时包含在结果字符串中。Each interpolated expression is resolved with the expression's value and included in the result string when the string is assigned. 有关详细信息,请参阅字符串内插(C# 参考)内插字符串(Visual Basic 参考)For more information, see String interpolation (C# Reference) and Interpolated strings (Visual Basic Reference).

复合格式设置功能受诸如以下方法的支持:The composite formatting feature is supported by methods such as the following:

复合格式字符串Composite Format String

复合格式字符串和对象列表将用作支持复合格式设置功能的方法的参数。A composite format string and object list are used as arguments of methods that support the composite formatting feature. 复合格式字符串由零个或多个固定文本段与一个或多个格式项混和组成。A composite format string consists of zero or more runs of fixed text intermixed with one or more format items. 固定文本是所选择的任何字符串,并且每个格式项对应于列表中的一个对象或装箱的结构。The fixed text is any string that you choose, and each format item corresponds to an object or boxed structure in the list. 复合格式设置功能返回新的结果字符串,其中每个格式项都被列表中相应对象的字符串表示形式取代。The composite formatting feature returns a new result string where each format item is replaced by the string representation of the corresponding object in the list.

可考虑使用以下 Format 代码段。Consider the following Format code fragment.

string name = "Fred";
String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now);
Dim name As String = "Fred"
String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now)

固定文本为“Name =”和“, hours =”。The fixed text is "Name = " and ", hours = ". 格式项为“{0}”和“{1:hh}”,前者的索引为 0,对应于对象 name,后者的索引为 1,对应于对象 DateTime.NowThe format items are "{0}", whose index is 0, which corresponds to the object name, and "{1:hh}", whose index is 1, which corresponds to the object DateTime.Now.

格式项语法Format Item Syntax

每个格式项都采用下面的形式并包含以下组件:Each format item takes the following form and consists of the following components:

{ index[,alignment][:formatString]}{ index[,alignment][:formatString]}

必须使用成对的大括号(“{”和“}”)。The matching braces ("{" and "}") are required.

索引组件Index Component

必需的索引组件(也叫参数说明符)是一个从 0 开始的数字,可标识对象列表中对应的项。The mandatory index component, also called a parameter specifier, is a number starting from 0 that identifies a corresponding item in the list of objects. 也就是说,参数说明符为 0 的格式项列表中的第一个对象,参数说明符为 1 的格式项列表中的第二个对象,依次类推。That is, the format item whose parameter specifier is 0 formats the first object in the list, the format item whose parameter specifier is 1 formats the second object in the list, and so on. 下面的示例包括四个参数说明符,编号为 0 到 3,用于表示小于 10 的质数:The following example includes four parameter specifiers, numbered zero through three, to represent prime numbers less than ten:

string primes;
primes = String.Format("Prime numbers less than 10: {0}, {1}, {2}, {3}",
                       2, 3, 5, 7 );
Console.WriteLine(primes);
// The example displays the following output:
//      Prime numbers less than 10: 2, 3, 5, 7
Dim primes As String
primes = String.Format("Prime numbers less than 10: {0}, {1}, {2}, {3}",
                       2, 3, 5, 7 )
Console.WriteLine(primes)
' The example displays the following output:
'      Prime numbers less than 10: 2, 3, 5, 7

通过指定相同的参数说明符,多个格式项可以引用对象列表中的同一个元素。Multiple format items can refer to the same element in the list of objects by specifying the same parameter specifier. 例如,可以将同一个数值设置为十六进制、科学记数法和数字格式,方法是通过指定复合格式字符串(例如:“0x{0:X} {0:E} {0:N}”),如以下示例所示。For example, you can format the same numeric value in hexadecimal, scientific, and number format by specifying a composite format string such as : "0x{0:X} {0:E} {0:N}", as the following example shows.

string multiple = String.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);
// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)
' The example displays the following output:
'      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

每个格式项都可以引用列表中的任一对象。Each format item can refer to any object in the list. 例如,如果有三个对象,可以指定“{1} {0} {2}”等复合格式字符串,以设置第二个、第一个和第三个对象的格式。For example, if there are three objects, you can format the second, first, and third object by specifying a composite format string like this: "{1} {0} {2}". 格式项未引用的对象会被忽略。An object that is not referenced by a format item is ignored. 如果参数说明符指定了超出对象列表范围的项,将引发运行时 FormatExceptionA FormatException is thrown at runtime if a parameter specifier designates an item outside the bounds of the list of objects.

对齐组件Alignment Component

可选的对齐组件是一个带符号的整数,指示首选的设置了格式的字段宽度。The optional alignment component is a signed integer indicating the preferred formatted field width. 如果 alignment 值小于设置了格式的字符串的长度,alignment 将被忽略,并使用设置了格式的字符串的长度作为字段宽度。If the value of alignment is less than the length of the formatted string, alignment is ignored and the length of the formatted string is used as the field width. 如果 alignment 为正数,字段中设置了格式的数据为右对齐;如果 alignment 为负数,字段中的设置了格式的数据为左对齐。The formatted data in the field is right-aligned if alignment is positive and left-aligned if alignment is negative. 如果需要填充,则使用空白。If padding is necessary, white space is used. 如果指定 alignment,则需要使用逗号。The comma is required if alignment is specified.

下面的示例定义两个数组,一个包含雇员的姓名,另一个则包含雇员在两周内的工作小时数。The following example defines two arrays, one containing the names of employees and the other containing the hours they worked over a two-week period. 复合格式字符串使 20 字符字段中的姓名左对齐,使 5 字符字段中的工作小时数右对齐。The composite format string left-aligns the names in a 20-character field, and right-aligns their hours in a 5-character field. 请注意“N1”标准格式字符串还用于设置带有小数位的小时数格式。Note that the "N1" standard format string is also used to format the hours with one fractional digit.

using System;

public class Example
{
   public static void Main()
   {
      string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George" };
      decimal[] hours = { 40, 6.667m, 40.39m, 82, 40.333m, 80,
                                 16.75m };

      Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");
      for (int ctr = 0; ctr < names.Length; ctr++)
         Console.WriteLine("{0,-20} {1,5:N1}", names[ctr], hours[ctr]);

   }
}
// The example displays the following output:
//       Name                 Hours
//
//       Adam                  40.0
//       Bridgette              6.7
//       Carla                 40.4
//       Daniel                82.0
//       Ebenezer              40.3
//       Francine              80.0
//       George                16.8
Module Example
   Public Sub Main()
      Dim names() As String = { "Adam", "Bridgette", "Carla", "Daniel",
                                "Ebenezer", "Francine", "George" }
      Dim hours() As Decimal = { 40, 6.667d, 40.39d, 82, 40.333d, 80,
                                 16.75d }

      Console.WriteLine("{0,-20} {1,5}", "Name", "Hours")
      Console.WriteLine()
      For ctr As Integer = 0 To names.Length - 1
         Console.WriteLine("{0,-20} {1,5:N1}", names(ctr), hours(ctr))
      Next
   End Sub
End Module
' The example displays the following output:
'       Name                 Hours
'
'       Adam                  40.0
'       Bridgette              6.7
'       Carla                 40.4
'       Daniel                82.0
'       Ebenezer              40.3
'       Francine              80.0
'       George                16.8

格式字符串组件Format String Component

可选的格式字符串组件是适合正在设置格式的对象类型的格式字符串。The optional formatString component is a format string that is appropriate for the type of object being formatted. 如果相应对象是数值,指定标准或自定义数字格式字符串;如果相应对象是 DateTime 对象,指定标准或自定义日期和时间格式字符串;或者,如果相应对象是枚举值,指定枚举格式字符串Specify a standard or custom numeric format string if the corresponding object is a numeric value, a standard or custom date and time format string if the corresponding object is a DateTime object, or an enumeration format string if the corresponding object is an enumeration value. 如果不指定 formatString,则对数字、日期和时间或者枚举类型使用常规(“G”)格式说明符。If formatString is not specified, the general ("G") format specifier for a numeric, date and time, or enumeration type is used. 如果指定 formatString,则需要使用冒号。The colon is required if formatString is specified.

下表列出了 .NET Framework 类库中支持预定义的格式字符串集的类型或类型的类别,并提供指向列出了支持的格式字符串的主题的链接。The following table lists types or categories of types in the .NET Framework class library that support a predefined set of format strings, and provides links to the topics that list the supported format strings. 请注意,字符串格式化是一个可扩展的机制,可使用该机制定义所有现有类型的新的格式字符串,并定义受应用程序定义的类型支持的格式字符串集。Note that string formatting is an extensible mechanism that makes it possible to define new format strings for all existing types as well as to define a set of format strings supported by an application-defined type. 有关详细信息,请参阅 IFormattableICustomFormatter 接口主题。For more information, see the IFormattable and ICustomFormatter interface topics.

类型或类型类别Type or type category 查看See
日期和时间类型(DateTimeDateTimeOffsetDate and time types (DateTime, DateTimeOffset) 标准日期和时间格式字符串Standard Date and Time Format Strings

自定义日期和时间格式字符串Custom Date and Time Format Strings
枚举类型(所有派生自 System.Enum 的类型)Enumeration types (all types derived from System.Enum) Enumeration Format StringsEnumeration Format Strings
数值类型(BigIntegerByteDecimalDoubleInt16Int32Int64SByteSingleUInt16UInt32UInt64Numeric types (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) Standard Numeric Format StringsStandard Numeric Format Strings

Custom Numeric Format StringsCustom Numeric Format Strings
Guid Guid.ToString(String)
TimeSpan 标准 TimeSpan 格式字符串Standard TimeSpan Format Strings

自定义 TimeSpan 格式字符串Custom TimeSpan Format Strings

转义大括号Escaping Braces

左大括号和右大括号被解释为格式项的开始和结束。Opening and closing braces are interpreted as starting and ending a format item. 因此,必须使用转义序列显示文本左大括号或右大括号。Consequently, you must use an escape sequence to display a literal opening brace or closing brace. 在固定文本中指定两个左大括号 ("{{") 以显示一个左大括号 ("{"),或指定两个右大括号 ("}}") 以显示一个右大括号 ("}")。Specify two opening braces ("{{") in the fixed text to display one opening brace ("{"), or two closing braces ("}}") to display one closing brace ("}"). 按照在格式项中遇到大括号的顺序依次解释它们。Braces in a format item are interpreted sequentially in the order they are encountered. 不支持解释嵌套的大括号。Interpreting nested braces is not supported.

解释转义大括号的方式会导致意外的结果。The way escaped braces are interpreted can lead to unexpected results. 例如,假设格式项为“{{{0:D}}}”,旨在显示左大括号、采用十进制数格式的数值和右大括号。For example, consider the format item "{{{0:D}}}", which is intended to display an opening brace, a numeric value formatted as a decimal number, and a closing brace. 但是,实际是按照以下方式解释该格式项:However, the format item is actually interpreted in the following manner:

  1. 前两个左大括号 ("{{") 被转义,生成一个左大括号。The first two opening braces ("{{") are escaped and yield one opening brace.

  2. 之后的三个字符 ("{0:") 被解释为格式项的开始。The next three characters ("{0:") are interpreted as the start of a format item.

  3. 下一个字符 ("D") 将被解释为 Decimal 标准数值格式说明符,但后面的两个转义大括号 ("}}") 生成单个大括号。The next character ("D") would be interpreted as the Decimal standard numeric format specifier, but the next two escaped braces ("}}") yield a single brace. 由于得到的字符串 ("D}") 不是标准数值格式说明符号,所以得到的字符串会被解释为用于显示字符串“D}”的自定义格式字符串。Because the resulting string ("D}") is not a standard numeric format specifier, the resulting string is interpreted as a custom format string that means display the literal string "D}".

  4. 最后一个大括号 ("}") 被解释为格式项的结束。The last brace ("}") is interpreted as the end of the format item.

  5. 显示的最终结果是字符串“{D}”。The final result that is displayed is the literal string, "{D}". 不会显示本来要设置格式的数值。The numeric value that was to be formatted is not displayed.

在编写代码时,避免错误解释转义大括号和格式项的一种方法是单独设置大括号和格式项的格式。One way to write your code to avoid misinterpreting escaped braces and format items is to format the braces and format item separately. 也就是说,在第一个格式设置操作中显示文本左大括号,在下一操作中显示格式项的结果,然后在最后一个操作中显示文本右大括号。That is, in the first format operation display a literal opening brace, in the next operation display the result of the format item, then in the final operation display a literal closing brace. 下面的示例阐释了这种方法。The following example illustrates this approach.

int value = 6324;
string output = string.Format("{0}{1:D}{2}", 
                             "{", value, "}");
Console.WriteLine(output);
// The example displays the following output:
//       {6324}                            
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}", _
                                     "{", value, "}")
Console.WriteLine(output)   
' The example displays the following output:
'       {6324}

处理顺序Processing Order

如果对复合格式设置方法的调用包括其值不为 IFormatProvidernull 参数,则运行时会调用其 IFormatProvider.GetFormat 方法来请求 ICustomFormatter 实现。If the call to the composite formatting method includes an IFormatProvider argument whose value is not null, the runtime calls its IFormatProvider.GetFormat method to request an ICustomFormatter implementation. 如果此方法能够返回 ICustomFormatter 实现,那么它将在复合格式方法调用期间缓存。If the method is able to return an ICustomFormatter implementation, it's cached for the duration of the call of the composite formatting method.

如下所示,将参数列表中与格式项对应的每个值转换为字符串:Each value in the parameter list that corresponds to a format item is converted to a string as follows:

  1. 如果要设置格式的值为 null,则将返回空字符串 String.EmptyIf the value to be formatted is null, an empty string String.Empty is returned.

  2. 如果 ICustomFormatter 实现可用,则运行时将调用其 Format 方法。If an ICustomFormatter implementation is available, the runtime calls its Format method. 它向方法传递格式项的 formatString 值(若有)或 null(若无)以及 IFormatProvider 实现 。It passes the method the format item's formatString value, if one is present, or null if it's not, along with the IFormatProvider implementation. 如果对 ICustomFormatter.Format 方法的调用返回 null,则继续执行下一步骤,将返回 ICustomFormatter.Format 调用的结果。If the call to the ICustomFormatter.Format method returns null, execution proceeds to the next step; otherwise, the result of the ICustomFormatter.Format call is returned.

  3. 如果该值实现 IFormattable 接口,则调用此接口的 ToString(String, IFormatProvider) 方法。If the value implements the IFormattable interface, the interface's ToString(String, IFormatProvider) method is called. 如果格式项中存在 formatString 值,则向方法传递该值;如果不存在该值,则传递 nullThe method is passed the formatString value, if one is present in the format item, or null if it's not. 按如下方式确定 IFormatProvider 自变量:The IFormatProvider argument is determined as follows:

  4. 调用类型的无参数的 ToString 方法(该方法将重写 Object.ToString() 或继承其基类的行为)。The type's parameterless ToString method, which either overrides Object.ToString() or inherits the behavior of its base class, is called. 在这种情况下,如果格式项中存在 formatString 组件指定的格式字符串,则将忽略该字符串 。In this case, the format string specified by the formatString component in the format item, if it's present, is ignored.

前面的步骤执行完毕之后应用对齐。Alignment is applied after the preceding steps have been performed.

代码示例Code Examples

下面的示例显示使用复合格式设置创建的一个字符串和使用对象的 ToString 方法创建的另一个字符串。The following example shows one string created using composite formatting and another created using an object's ToString method. 两种格式设置类型产生相同的结果。Both types of formatting produce equivalent results.

string FormatString1 = String.Format("{0:dddd MMMM}", DateTime.Now);
string FormatString2 = DateTime.Now.ToString("dddd MMMM");
Dim FormatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim FormatString2 As String = DateTime.Now.ToString("dddd MMMM") 

假定当前日期是五月的星期四,那么在美国英语区域性中上述示例中的两个字符串的值都是 Thursday May英语区域性。Assuming that the current day is a Thursday in May, the value of both strings in the preceding example is Thursday May in the U.S. English culture.

Console.WriteLine 提供与 String.Format 相同的功能。Console.WriteLine exposes the same functionality as String.Format. 这两种方法的唯一差异是 String.Format 将其结果作为字符串返回,而 Console.WriteLine 将结果写入与 Console 对象关联的输出流中。The only difference between the two methods is that String.Format returns its result as a string, while Console.WriteLine writes the result to the output stream associated with the Console object. 下面的示例使用 Console.WriteLine 方法将 MyInt 的值的格式设置为货币值。The following example uses the Console.WriteLine method to format the value of MyInt to a currency value.

int MyInt = 100;
Console.WriteLine("{0:C}", MyInt);
// The example displays the following output 
// if en-US is the current culture:
//        $100.00
Dim MyInt As Integer = 100
Console.WriteLine("{0:C}", MyInt)
' The example displays the following output
' if en-US is the current culture:
'        $100.00

下面的示例说明为多个对象设置格式,包括用两种不同的方式为一个对象设置格式。The following example demonstrates formatting multiple objects, including formatting one object two different ways.

string myName = "Fred";
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
      myName, DateTime.Now));
// Depending on the current time, the example displays output like the following:
//    Name = Fred, hours = 11, minutes = 30                 
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}", _
                  myName, DateTime.Now))
' Depending on the current time, the example displays output like the following:
'    Name = Fred, hours = 11, minutes = 30                 

下面的示例演示了对齐在格式设置中的使用方式。The following example demonstrates the use of alignment in formatting. 设置了格式的参数放置在竖线字符 (|) 之间以突出显示得到的对齐。The arguments that are formatted are placed between vertical bar characters (|) to highlight the resulting alignment.

string myFName = "Fred";
string myLName = "Opals";
int myInt = 100;
string FormatFName = String.Format("First Name = |{0,10}|", myFName);
string FormatLName = String.Format("Last Name = |{0,10}|", myLName);
string FormatPrice = String.Format("Price = |{0,10:C}|", myInt); 
Console.WriteLine(FormatFName);
Console.WriteLine(FormatLName);
Console.WriteLine(FormatPrice);
Console.WriteLine();

FormatFName = String.Format("First Name = |{0,-10}|", myFName);
FormatLName = String.Format("Last Name = |{0,-10}|", myLName);
FormatPrice = String.Format("Price = |{0,-10:C}|", myInt);
Console.WriteLine(FormatFName);
Console.WriteLine(FormatLName);
Console.WriteLine(FormatPrice);
// The example displays the following output on a system whose current
// culture is en-US:
//          First Name = |      Fred|
//          Last Name = |     Opals|
//          Price = |   $100.00|
//
//          First Name = |Fred      |
//          Last Name = |Opals     |
//          Price = |$100.00   |
   Dim myFName As String = "Fred"
   Dim myLName As String = "Opals"

   Dim myInt As Integer = 100
   Dim FormatFName As String = String.Format("First Name = |{0,10}|", myFName)
   Dim FormatLName As String = String.Format("Last Name = |{0,10}|", myLName)
   Dim FormatPrice As String = String.Format("Price = |{0,10:C}|", myInt)
   Console.WriteLine(FormatFName)
   Console.WriteLine(FormatLName)
   Console.WriteLine(FormatPrice)
   Console.WriteLine()
   
   FormatFName = String.Format("First Name = |{0,-10}|", myFName)
   FormatLName = String.Format("Last Name = |{0,-10}|", myLName)
   FormatPrice = String.Format("Price = |{0,-10:C}|", myInt)
   Console.WriteLine(FormatFName)
   Console.WriteLine(FormatLName)
   Console.WriteLine(FormatPrice)
   ' The example displays the following output on a system whose current
   ' culture is en-US:
   '          First Name = |      Fred|
   '          Last Name = |     Opals|
   '          Price = |   $100.00|
   '
   '          First Name = |Fred      |
   '          Last Name = |Opals     |
   '          Price = |$100.00   |

请参阅See also