在.NET程序中,格式控制字符串几乎无处不在,即使是最简单的"Hello, World"程序,因为它们是所有Console.Write()和Console.WriteLine()方法的隐式组成部分。只有很少使用的不接受参数的重载版本不需要格式控制字符串;对于其他版本,它是必需的参数。同样适用于TextStrimg.WriteLine()、string.Format()、StringBuilder.AppendFormat()等方法。
这引出了参数数组的话题。如果列表有三项或更少的项目,可以不用正式定义一个数组,只需将它们作为第二个、第三个和第四个参数列出即可。然而,在内部,它们构成了一个数组,即使只是一个隐式的数组。
一个简短的C#控制台程序很好地演示了上述所有要点。下面是一个完整的程序,总共89行,其中50行是注释,另外14行完全是空白,剩下25行实际代码。在这25行中,有4行定义了常量,1行导入了System命名空间,9行打开或关闭作用域,剩下12行做了一些有用的事情。
using System;
namespace FormatItemCountDemo
{
class Program
{
static void Main(string[] pastrCmdLneArgs)
{
const string ANNOUNCE_1 = @"
Total Format Items in Array = {0}";
const string ANNOUNCE_2 = @"
{1} Total Format Items in Array = {0}";
const string ANNOUNCE_3 = @"
{1} Total Format Items in Array = {0}{2}";
const string DUMMY_FORMAT_ITEM_2 = @"
(Dummy Format Item 2, with leading space)";
int intNStrings = 0;
Console.WriteLine("Begin format item counting demonstration.\r\n");
Console.WriteLine(ANNOUNCE_1, ++intNStrings, Environment.NewLine);
Console.WriteLine(ANNOUNCE_2, ++intNStrings, Environment.NewLine);
try
{
Console.WriteLine(ANNOUNCE_3, ++intNStrings, Environment.NewLine);
}
catch (FormatException errBadFormatControlString)
{
Console.WriteLine("{2}{0} exception{2}{2} Exception Message: {1}", errBadFormatControlString.GetType().FullName, errBadFormatControlString.Message, Environment.NewLine);
}
Console.WriteLine(ANNOUNCE_3, intNStrings, Environment.NewLine, DUMMY_FORMAT_ITEM_2);
Console.WriteLine("{0}Done!{0}", Environment.NewLine);
}
}
}
创建一个新的控制台程序项目,在Visual Studio中粘贴上述所有内容,并构建。如果想在交互式调试器中运行时看到任何内容,可以在主程序的关闭大括号上设置一个断点。或者,在构建完成后,可以在输出目录中打开命令提示符,并执行程序,就像创建下图时所做的那样。
大多数有趣的部分都在嵌入式注释中覆盖了。如果没有注意,消息指示数组中的格式项目数量;它们真正传达的是数组必须包含的格式控制字符串的最小格式项目数量。
除了激发本文发现的特点外,代码的一个值得关注的特性是在Console.WriteLine()、string.Format()等格式化字符串时对参数数组的注释方式。由于前两行是从同一个数组中打印出来的,很明显未使用的第二个项目被完全忽略了。除了浪费一些字节之外,数组中的额外项目是完全无害的。
第三个打印语句被包裹在一个try/catch块中,以防止未处理的异常导致程序崩溃。在第三个打印语句尝试执行时生成的异常报告之后,第四个语句使用了相同的格式控制字符串,但在项目数组中添加了另一个项目。有了三个项目,数组覆盖了格式控制字符串中的格式项目,打印成功。