一、概述
特殊字符是预定义的上下文字符,用于修饰最前面插入了此类字符的程序元素(文本字符串,标识符或属性名称)。C#支持以下特殊字符:
- @:逐字字符串标识符字符
- $: 内插入字符串字符
二、$-- 字符串内插
$
字符将字符串字面量标识为内插字符串。 内插字符串是可能包含内插表达式的字符串文本 。 将内插字符串解析为结果字符串时,带有内插表达式的项会替换为表达式结果的字符串表示形式。
字符串内插为格式化字符串提供了一种可读性和便捷性更高的方式。它比字符串复合格式设置更容易。
public static void Main(string[] arg) { var name = "Mark"; var date = DateTime.Now; Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date); Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now."); }
从C#10开始,可以使用内插字符串来初始化常量字符串。仅当内插字符串中的所有内插表达式也是常量字符串时,才可以执行此操作。
2.1 内插字符串的结构
若要将字符串标识为内插字符串,可在该字符串前面加上$
符号。字符串字面量开头的$
和"
之间不能有任何空格。
具备内插表达式的项的结构如下所示:
{<interpolationExpression>[,<alignment>][:<formatString>]}
- interpolationExpression 生成需要设置格式的结果的表达式。null的字符串表示形式为String.Empty。
- alignment 常数表达式,它的值定义表达式结果的字符串表示形式中的最小字符数。 如果值为正,则字符串表示形式为右对齐;如果值为负,则为左对齐。
- formatString 受表达式结果类型支持的格式字符串。
public static void Main(string[] arg) { Console.WriteLine($"|{"Left",-7}|{"Right",7}|"); const int FieldWidthRightAligned = 20; Console.WriteLine($"{Math.PI,FieldWidthRightAligned} - default formatting of the pi number"); Console.WriteLine($"{Math.PI,FieldWidthRightAligned:F2} - display only three decimal digits"); }
从 C# 11 开始,可以在内插表达式中使用换行符,以使表达式的代码更具可读性。
下面的示例展示了换行符如何提高涉及模式匹配的表达式的可读性:
public static void Main(string[] arg) { var safetyScore = 80; string message = $"The usage policy for {safetyScore} is" + $" {safetyScore switch { > 90 => "Unlimited usage", > 80 => "General usage, with daily safety check", > 70 => "Issues must be addressed within 1 week", > 50 => "Issues must be addressed within 1 day", _ => "Issues must be addressed before continued use", }}"; Console.WriteLine(message); }
2.2 内插原始字符串字面量
从C# 11开始,可以使用内插原始字符串字面量。如以下示例所示:
int X=2; int Y=3; var pointMessage = $"""The point"{X},{Y}" is {Math.Sqrt(X*X+Y*Y):F3} from the origin"""; Console.WriteLine(pointMessage);
要在结果字符串嵌入{
和}
字符,请让内插原始字符串字面量以多个$
字符开头。执行此操作时,任何长度短$
字符数的{
和}
字符序列都会嵌入到结果字符串中。若要将任何内插表达式包含该字符串中,需要使用与$
字符数相同的大括号数。
如以下示例所示:
int X = 2; int Y = 3; var pointMessage = $$"""{The point {{{X}}, {{Y}}} is {{Math.Sqrt(X * X + Y * Y):F3}} from the origin}"""; Console.WriteLine(pointMessage);
内插原始字符串字面量以两个$
字符开头。需要将每个内插表达式放在双大括号{{
和}}
之间。单个大括号嵌入到结果字符串中,如果需要重复的{
或}
字符嵌入结果字符串中,请使用相应增加的$
字符数来指定内插原始字符串字面量。
2.3 特殊字符
要在内插字符串生成的文本中包含大括"{“或”}",请使用两个大括号,即“{{”或“}}”。有关详细信息。
因为冒号(“:”)在内插表达式中具有特殊含义,为了在内插表达式使用条件运算符,请将表达式放在括号内。
下面示例演示了如何在结果字符串中包含大括号。下面示例演示如何使用条件运算符:
string name = "Horace"; int age = 34; Console.WriteLine($"He asked, \"Is your name {name}?\", but didn't wait for a reply :-{{"); Console.WriteLine($"{name} is {age} year{(age == 1 ? "" : "s")} old.");
内插逐字字符串以$
和@
字符开头。可以按任意顺序使用$
和@:
$@"..."
和@$"..."
均为有效的内插逐字字符串。
2.4 内插字符串编译
从C#10和.NET 6开始,编译器会检查内插字符串是否被分配给满足内插字符串处理程序模式要求的类型。内插字符串处理程序是一种内插字符串转换为结果字符串的类型。当内插字符串的类型为string时,它由System.Runtime.CompilerServices.DefaultInterpolatedStringHandle处理。
在C# 10之前,如果内插字符串类型为String,则通常将其转换为String.Format方法调用。如果分析的行为等同于串联,则编译器可将String.Format替换为String.Concat。
如果内插字符串类型为IFormattable或FormattableString,则编译器会生成对FormattableStringFactory.Create方法的调用。
三、@-- 逐字字符串标识符
@
特殊字符用作原义标识符。通过以下方式使用它:
- 指示将原义解释字符串。
@
字符在此实例中定义原义标识符。简单转义序列、十六进制转义序列和Unicode
转义序列都将字面解释。只有引号转义序列(“”)不会被字面解释;因为它生成一个双引号。此外。如果是逐字内插字符串,大括号转义序列({{
和}}
)不按字面解释;它们会生成单个大括号字符。
string filename1 = @"c:\documents\files\u0066.txt"; string filename2 = "c:\\documents\\files\\u0066.txt"; Console.WriteLine(filename1); Console.WriteLine(filename2);
使用C#关键字作为标识符。@
字符可作为代码元素的前缀,编译器将把此代码元素解释为标识符而非C#关键字。
string[] @for={"John","James","Joan","Jamie"}; for(int ctr = 0; ctr<@for.Length;ctr++) { Console.WriteLine($"Here is your gift, {@for[ctr]}!"); }
- 使编译器在命名冲突的情况下区分两种属性。属性是派生自
Attribute
的类。其类型名称通常包含后缀Attribute
,但编译器不会强制进行转换。
四、“”“–原始字符串文本
原始字符串字面量以至少三个双引号(“
)字符开始和结束:
var singleLine = """This is a "raw string literal". It can contain characters like \, ' and ".""";
原始字符串字面量可以包含多行:
var xml = """ <element attr="content"> <body> </body> </element> """;
以下规则控制多行原始字符串字面量的解释:
- 左引号和右引号字符必须位于各自的行中
- 右引号左侧的任何空格将从原始字符串字面量的所有行中删除。
- 将忽略同一行中左引号后面的空格。
- 字符串字面量中仅包含左引号后面的空格行
可能需要创建包含三个或更多连续双引号字符的原始字符串字面量。 原始字符串字面量可以至少三个双引号字符的序列开始和结束。 如果字符串字面量包含三个连续双引号,则以四个双引号字符开始和结束原始字符串字面量:
var moreQuotes = """" As you can see,"""Raw string literals""" can start and end with more than three double-quotes when needed."""";
原始字符串字面量还可以与内插字符串结合使用,以在输出字符串中嵌入{
和}
字符。在内插的原始字符串字面量中使用多个$
字符,以在输出字符串中嵌入{
和}
字符,而无需对这些字符进行转义。