复合格式设置

 

.NET Framework 复合格式设置功能使用对象列表和复合格式字符串作为输入。 复合格式字符串由固定文本和索引占位符混和组成,其中索引占位符称为格式项,对应于列表中的对象。 格式设置操作产生的结果字符串由原始固定文本和列表中对象的字符串表示形式混和组成。

复合格式设置功能受诸如以下方法的支持:

复合格式字符串和对象列表将用作支持复合格式设置功能的方法的参数。 复合格式字符串由零个或多个固定文本段与一个或多个格式项混和组成。 固定文本是所选择的任何字符串,并且每个格式项对应于列表中的一个对象或装箱的结构。 复合格式设置功能返回新的结果字符串,其中每个格式项都被列表中相应对象的字符串表示形式取代。

可考虑使用以下 Format 代码段。

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

固定文本为“Name = ”和“, hours = ”。 格式项为“{0}”和“{1:hh}”,前者的索引为 0,对应于对象 myName,后者的索引为 1,对应于对象 DateTime.Now

每个格式项都采用下面的形式并包含以下组件:

{ index[,alignment][:formatString]}

必须使用成对的大括号(“{”和“}”)。

索引组件

强制“索引”组件(也叫参数说明符)是一个从 0 开始的数字,可标识对象列表中对应的项。 也就是说,参数说明符为 0 的格式项列表中的第一个对象,参数说明符为 1 的格式项列表中的第二个对象,依次类推。 下面的示例包括五个参数说明符,用于表示小于 10 的质数:

   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

通过指定相同的参数说明符,多个格式项可以引用对象列表中的同一个元素。 例如,通过指定诸如“0x{0:X} {0:E} {0:N}”的复合格式字符串,可以将同一个数值设置为十六进制、科学记数法和数字格式,如下面的示例所示。

   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

每个格式项都可以引用列表中的任一对象。 例如,如果有三个对象,则可以通过指定类似于“{1} {0} {2}”的复合格式字符串来设置第二、第一和第三个对象的格式。 格式项未引用的对象会被忽略。 如果参数说明符指定了超出对象列表范围的项,将引发运行时 FormatException

对齐组件

可选的“对齐”组件是一个带符号的整数,指示首选的设置了格式的字段宽度。 如果“对齐”值小于设置了格式的字符串的长度,“对齐”会被忽略,并且使用设置了格式的字符串的长度作为字段宽度。 如果“对齐”为正数,字段中设置了格式的数据为右对齐;如果“对齐”为负数,字段中的设置了格式的数据为左对齐。 如果需要填充,则使用空白。 如果指定 alignment,就需要使用逗号。

下面的示例定义两个数组,一个包含雇员的姓名,另一个则包含雇员在两周内的工作小时数。 复合格式字符串使 20 字符字段中的姓名左对齐,使 5 字符字段中的工作小时数右对齐。 请注意“N1”标准格式字符串还用于设置带有小数位的小时数格式。

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

格式字符串组件

可选的“格式字符串”组件是适合正在设置格式的对象类型的格式字符串。 如果相应的对象是数值,则指定标准或自定义的数字格式字符串;如果相应的对象是 DateTime 对象,则指定标准或自定义的日期和时间格式字符串;或者,如果相应的对象是枚举值,则指定枚举格式字符串。 如果不指定 formatString,则对数字、日期和时间或者枚举类型使用常规(“G”)格式说明符。 如果指定 formatString,则需要使用冒号。

下表列出了 .NET Framework 类库中支持预定义的格式字符串集的类型或类型的类别,并提供指向列出了支持的格式字符串的主题的链接。 请注意,字符串格式化是一个可扩展的机制,可使用该机制定义所有现有类型的新的格式字符串,并定义受应用程序定义的类型支持的格式字符串集。 有关详细信息,请参阅 IFormattableICustomFormatter 接口主题。

类型或类型类别请参阅
日期和时间类型(DateTimeDateTimeOffset标准日期和时间格式字符串

 自定义日期和时间格式字符串
枚举类型(所有派生自 System.Enum 的类型)枚举格式字符串
数值类型(BigIntegerByteDecimalDoubleInt16Int32Int64SByteSingleUInt16UInt32UInt64标准数字格式字符串

 自定义数字格式字符串
GuidGuid.ToString(String)
TimeSpan标准 TimeSpan 格式字符串

 自定义的 TimeSpan 格式字符串

转义大括号

左大括号和右大括号被解释为格式项的开始和结束。 因此,必须使用转义序列显示文本左大括号或右大括号。 在固定文本中指定两个左大括号 ("{{") 以显示一个左大括号 ("{"),或指定两个右大括号 ("}}") 以显示一个右大括号 ("}")。 按照在格式项中遇到大括号的顺序依次解释它们。 不支持解释嵌套的大括号。

解释转义大括号的方式会导致意外的结果。 例如,考虑要显示一个左大括号、一个设置为十进制数格式的数值和一个右大括号的格式项“{{{0:D}}}”。 但是,实际是按照以下方式解释该格式项:

  1. 前两个左大括号 ("{{") 被转义,生成一个左大括号。

  2. 之后的三个字符 ("{0:") 被解释为格式项的开始。

  3. 下一个字符 ("D") 将被解释为 Decimal 标准数值格式说明符,但后面的两个转义大括号 ("}}") 生成单个大括号。 由于得到的字符串 ("D}") 不是标准数值格式说明符号,所以得到的字符串会被解释为用于显示字符串“D}”的自定义格式字符串。

  4. 最后一个大括号 ("}") 被解释为格式项的结束。

  5. 显示的最终结果是字符串“{D}”。 不会显示本来要设置格式的数值。

在编写代码时,避免错误解释转义大括号和格式项的一种方法是单独设置大括号和格式项的格式。 也就是说,在第一个格式设置操作中显示文本左大括号,在下一操作中显示格式项的结果,然后在最后一个操作中显示文本右大括号。 下面的示例阐释了这种方法。

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

处理顺序

如果对复合格式设置方法的调用包括其值不为 IFormatProvidernull 参数,则运行时会调用其 IFormatProvider.GetFormat 方法来请求 ICustomFormatter 实现。 如果此方法能够返回 ICustomFormatter 实现,则将对其进行缓存以供稍后使用。

通过执行以下步骤,将参数列表中与格式项对应的每个值转换为字符串。 如果符合前三个步骤中的任一条件,则在此步骤中返回值的字符串表示形式,并且不执行后续步骤。

  1. 如果要设置格式的值为 null,则将返回空字符串 ("")。

  2. 如果 ICustomFormatter 实现可用,则运行时将调用其 Format 方法。 如果格式项中存在 formatString 值,则将向方法传递该值,或如果不存在,则将 nullIFormatProvider 实现一起传递。

  3. 如果该值实现 IFormattable 接口,则调用此接口的 ToString(String, IFormatProvider) 方法。 如果格式项中存在 formatString 值,则向方法传递该值;如果不存在该值,则传递 null。 按如下方式确定 IFormatProvider 参数:

  4. 调用类型的无参数的 ToString 方法(该方法将重写 Object.ToString() 或继承其基类的行为)。 在这种情况下,如果格式项中存在 formatString 组件指定的格式字符串,则将忽略该字符串。

前面的步骤执行完毕之后应用对齐。

下面的示例显示使用复合格式设置创建的一个字符串和使用对象的 ToString 方法创建的另一个字符串。 两种格式设置类型产生相同的结果。

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

假定当前日期是五月的星期四,那么在美国英语区域性中上述示例中的两个字符串的值都是 Thursday May

Console.WriteLine 提供与 String.Format 相同的功能。 这两种方法的唯一差异是 String.Format 将其结果作为字符串返回,而 Console.WriteLine 将结果写入与 Console 对象关联的输出流中。 下面的示例使用 Console.WriteLine 方法将 MyInt 的值的格式设置为货币值。

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

下面的示例说明为多个对象设置格式,包括用两种不同的方式为一个对象设置格式。

      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                 

下面的示例演示了对齐在格式设置中的使用方式。 设置了格式的参数放置在竖线字符 (|) 之间以突出显示得到的对齐。

      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   |

WriteLine
String.Format
格式化类型
标准数字格式字符串
自定义数字格式字符串
标准日期和时间格式字符串
自定义日期和时间格式字符串
标准 TimeSpan 格式字符串
自定义的 TimeSpan 格式字符串
枚举格式字符串

显示: