第5条:用FormattableString取代专门为特定区域而写的字符串
上一条讲解了C#语言中的一项新特性,也就是内插字符串,开发者可以通过这种字符串更加便捷地把变量的值与某些信息结合起来,从而构建出格式良好的文本信息。有些程序还需要根据区域和语言做出不同的处理,为此,开发者必须更加深入地了解内插字符串的用法,以便更好地应对这些需求。
语言设计团队其实仔细地考虑过如何才能令字符串支持不同的区域。他们想要创建一套能够支持任意地区(culture)的文本生成系统,同时还要令这套系统可以方便地用在那种只针对单一地区的场合中。权衡了这两方面的目标之后,可以看出,如果按照地区对内插字符串分别加以处理,那么会令系统变得更加复杂。
开发者使用内插字符串的时候,其实只是想用以$开头的字符串来生成另一个字符串,C#的字符串机制也正是这样运作的。它会把内插字符串的解读结果隐式地转换成string或FormattableString。
比方说,如果采用下面这种最为简单的写法,那么内插字符串就会解读为string:
接下来的这行代码会令C#系统根据内插字符串的解读结果来创建一个对象,该对象所属的类型继承自FormattableString:
最后这行代码声明了隐式类型的局部变量,该变量的类型应该是string。编译好的程序码会生成相应的string对象,并将其赋给该变量:
编译器会根据应该输出的信息所具有的运行期类型来产生不同的程序码,其中,用来创建字符串的那一部分程序码会根据执行该程序的计算机当前所在的区域来设定字符串的格式。如果在美国运行代码,那么double值的整数与小数之间会用句点(.)来分隔,如果在欧洲国家运行,那么分隔符则是逗号(,)。
开发者可以利用编译器的类型判定机制来直接生成string或Formattable-String,也可以编写方法,把内插字符串的解读结果转换成适用于某个地区的字符串。比方说下面这两个方法就可以把FormattableString转换成针对特定语言与特定地区的string。
这两个方法都只接受一个参数,也就是类型为FormattableString的src。如果以FormattableString对象为实参来调用,它们就会分别采用特定的区域及语言设置(第一个方法采用德国和德语,第二个方法采用加拿大和法语),把参数转换成string。你也可以在内插字符串的解读结果上面直接调用这两个方法。
首先要注意,不要给这些方法编写以string为参数的重载版本,否则,编译器在面对既可以选string版本又可以选FormattableString版本的情况下,会创建出生成string的程序码,进而调用以string为参数的那个版本。
此外还要注意,这两个方法都没有设计成扩展方法,因为编译器在判断自己应该生成string还是FormattableString的时候,会考虑生成的这个字符串是否位于点(.)运算符的左侧。如果是这样,那么就会生成string,而非FormattableString。内插字符串的一项设计目标是想令开发者能够将其与现有的string类顺畅地结合起来,同时,还必须能够应对全球各地的多种语言。在后面这种情况下,开发者虽然需要多写一点代码,但这些代码写起来应该比较简单。
单凭字符串内插功能还不足以使应用程序能够应对世界上的所有语言,或是能够专门为某种语言做出特殊的处理。如果程序只是针对当前区域而生成文本,那么直接使用内插字符串就够了,这样反而可以避免多余的操作。反之,如果需要针对特定的地区及语言来生成字符串,那么就必须根据内插字符串的解读结果来创建FormattableString,并将其转换成适用于该地区及该语言的字符串。