自从有了编程这门职业,开发者就需要把计算机里面所保存的信息转换成更便于人类阅读的格式。C#语言中的相关API可以追溯到几十年前所诞生的C语言,但是这些老的习惯现在应该改变,因为C#6.0提供了内插字符串(Interpolated String)这项新的功能可以用来更好地设置字符串的格式。
与设置字符串格式所用的旧办法相比,这项新功能有很多好处。开发者可以用它写出更容易阅读的代码,编译器也可以用它实现出更为完备的静态类型检查机制,从而降低程序出错的概率。此外,它还提供了更加丰富的语法,令你可以用更为合适的表达式来生成自己想要的字符串。
String.Format()函数虽然可以运作,但是会导致一些问题,开发者必须对生成的字符串进行测试及验证,才有可能发现这些问题。所有的替换操作都是根据格式字符串里面的序号来完成的,而编译器又不会去验证格式字符串后面的参数个数与有待替换的序号数量是否相等。如果两者不等,那么程序在运行的时候就会抛出异常。
还有一个更为隐晦的问题:格式字符串中的序号与params数组中的位置相对应,而阅读代码的人却不太容易看出来数组中的那些字符串是不是按照正确顺序排列的。必须运行代码,并仔细检查程序所生成的字符串,才能够确认这一点。
这些困难当然都是可以克服的,但会花费较多的时间,因此,不妨改用C#语言所提供的新特性来简化编写代码工作。这项新特性指的就是内插字符串。
内插字符串以$开头,它不像传统的格式字符串那样把序号放在一对花括号里面,并用其指代params数组中的对应元素,而是可以直接在花括号里面编写C#表达式。这使得代码更便于阅读,因为开发者可以直接在字符串里面看到这些有待替换的内容分别对应于什么样的表达式。采用这种办法来生成字符串是很容易验证其结果的。由于表达式直接出现在字符串中而不用单独写在字符串后面,因此,每一个有待替换的部分都能与替换该部分所用的那条表达式对应起来,不会出现双方的总数量不相符的情况。此外,这种写法也使得开发者不太会把表达式之间的顺序写错。
这样的语法糖(syntactic sugar)是很好的。将这种新特性融入日常的编程工作之后,你就会看到内插字符串是多么强大了。
首先,还是谈谈可以嵌入花括号里的那些表达式在写法上有什么样的限制。
之所以把花括号里的代码叫作表达式而不泛称为语句,是因为不能使用if/else或while等控制流语句来做替换。如果需要根据控制流做替换,那么必须把这些逻辑写成方法,然后在内插字符串里面嵌入该方法的调用结果。
字符串内插机制是通过库代码来完成的,那些代码与当前的string.Format()类似(至于如何实现国际化,请参见本章第5条)。内插字符串会在必要的时候把变量从其他类型转为string类型。比方说,下面这个内插字符串就是如此:
Console.WriteLine(
$"Π值为:{Math.PI.ToString()}"
);
花括号里面还可以嵌入字符串,凡是位于{和}之间的字符,就都会被当成这条表达式中的C#代码加以解析。(冒号例外,它用来表示其右侧的内容是格式说明符。)
这是个很好的特性,深入研究之后,你就会发现它实在是太奇妙了。例如在内插字符串里面还可以继续编写内插字符串。合理运用这种写法可以极大地简化编程工作。比方说,下面这种写法就能够在可以找到记录的情况下把这条记录中的信息显示出来,并在找不到记录的情况下打印出与之相应的序号:
List<String> rsts=new(){"0","","1","2","3",""};
foreach (var element in rsts.Dump())
{ Console.WriteLine($@"记录是: {(element != "" ? element :
$"null")}");}