C# $字符串插值的使用

2025-08-26 248624 日常编程

本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧

目录
  • $ 字符
  • 使用方式
    • 创建内插字符串
    • 包含不同的数据类型
    • 控制内插表达式的格式
    • 控制内插表达式的对齐方式
    • 内插表达式中使用转义序列
    • 内插表达式中使用 ?: 运算符
  • 实现细节
    • string.Concat
    • string.Format
    • FormattableString
    • constants(C# 10)
    • Interpolated string handlers(C# 10)
  • Reference

    $ 字符

    字符串插值(String Interpolation)有许多的实现方式,其中使用 $ 字符在现代 C# 中时比较推荐的方式,它提供类似于 String.Format 的效果。

    实际根据 $ 使用场景的不同,编译器会选择用不同的方式实现字符串插值,String.Format 只是其中一种,具体见 实现细节

    如下分别为使用 $String.Format的示例:

    int value = 3;
    Debug.Log($"Value is {value}");
    Debug.Log(String.Format("Value is {0}", value));
    

    输出结果为:

    Value is 3
    Value is 3

    使用方式

    创建内插字符串

    字符串插值(String Interpolation) 是用来将表达式插入到字符串中的方式,简单的示例如下所示:

    string name = "wxj";
    Debug.Log($"Hello,{name}.");
    

    输出结果为:

    Hello,wxj.

    其中 $"Hello,{name}.") 被称为 内插字符串表达式(interpolated string expression)(下简称 内插表达式),最后输出的 Hello,wxj. 被称为 结果字符串(result string)

    由上例可以看出字符串插值的两个必要因素:

    1. 在字符串前需要有 $ 字符标记,且该字符与后续的 " 间不能有空格。
    2. 在内插表达式内部可以有一个或多个 {} ,其中包含着任何返回结果的 C# 表达式,表达式的返回值也可以为 null。

    包含不同的数据类型

    对于内插表达式中的各 C# 表达式可以是任何类型的,如下所示:

    var item = (Name: "eggplant", Price: 1.99m, perPackage: 3);
    var date = DateTime.Now;
    Debug.Log($"On {date}, the price of {item.Name} was {item.Price} per {item.perPackage} items.");
    

    输出结果为:

    On 12/10/2021 8:26:07 AM, the price of eggplant was 1.99 per 3 items.

    可以看到该内插字符串表达式中包含有各种类型的表达式(stringDecimalintDeltaTime),在最终的结果中都被正确的解析。

    内插字符串表达式,各表达式都会被转换为 string,且规则如下:

    1. 如果表达式结果为 null ,将其转换为空字符串。
    2. 如果表达式结果不为 null,对其调用 ToString 函数。

    控制内插表达式的格式

    在内插表达式中,还可以控制各表达式转换到 string 时的格式,如下所示:

    DateTime date = DateTime.Now;
    float value = 1.12345678f;
    Debug.Log($"On {date}, value is {value}");
    Debug.Log($"On {date:d}, value is {value:f3}");
    

    输出结果为:

    On 12/10/2021 8:39:56 AM, value is 1.123457
    On 12/10/2021, value is 1.123

    在内插表达式中的各表达式中可以通过 : 后加控制的字符格式化输出。如上例中的 df3 即为控制字符。

    : 后的控制字符,相当于在调用 ToString 时作为形参控制表达式的输出。
    上述表达式等同于:

    Debug.Log("On " + date.ToString("d") + ", value is " + value.ToString("f3"));
    

    控制内插表达式的对齐方式

    在内插表达式中的个表达式中可以通过 , 后加数字来控制字符宽度和对其方式,如下所示:

    var inventory = new Dictionary()
    {
        ["hammer, ball pein"] = 14,
        ["hammer, ball pein a"] = 18,
        ["hammer, cross pein"] = 5,
        ["screwdriver, Phillips #2"] = 14
    };
    
    string result = $"|{"Item",-25}|{"Quantity",10}|\n";
    foreach (var item in inventory)
        result += $"|{item.Key,-25}|{item.Value,10}|\n";
    
    Debug.Log(result);
    

    输出结果为:

    |Item                     |  Quantity|
    |hammer, ball pein        |        14|
    |hammer, ball pein a      |        18|
    |hammer, cross pein       |         5|
    |screwdriver, Phillips #2 |        14|

    其中逗号后的数字,如果为负数,则输出为左对齐,如果为正数则右对齐。数字本身表示最少的字符数。因此如果显示系统中每个字符的宽度是不相等的话,如 ia 的宽度在某些显示系统下会有较大差异,则即使控制字符宽度也无法实现对其的效果。

    如下为相同输出结果在 Unity 的 Console 面板中的展示:

    表达式格式和对齐方式也可以一起设定,但需要首先设定对其方式,再设定格式。如下首先控制了左对齐,且字符数为 10 个,又设定输出格式为当前小时数:

    Debug.Log($"[{DateTime.Now,-10:HH}]");
    

    结果为:

    [10        ]

    内插表达式中使用转义序列

    如果要在内插表达式中可以使用转义序列,当需要多次使用转义序列时也可使用 原义标识符@ 替代。

    如下所示,分别使用使用了转义序列和原文标识符:

    string userName = "wxj";
    string stringWithEscapes = $"C:\\Users\\{userName}\\Documents";
    string verbatimInterpolated = $@"C:\Users\{userName}\Documents";
    Debug.Log(stringWithEscapes);
    Debug.Log(verbatimInterpolated);
    

    输出结果为:

    C:\Users\wxj\Documents
    C:\Users\wxj\Documents

    C# 8.0 后,$ 与 @ 的先后顺序不会造成任何影响。在早期版本中,必须先写 $ 再写 @。

    在内插表达式中,如果需要输入 {,则按如下方式处理:

    int[] values = new int[] { 1, 2 };
    Debug.Log($"Value is {{{values[0]}, {values[1]}}}");
    

    输出结果为:

    Value is {1, 2}

    也可以通过 $@ 的结合控制换行,如下:

    var publishDate = new DateTime(2017, 12, 14);
    string str = $@"This post published on {publishDate:yyyy-MM-dd} is about
    interpolated strings.";
    Debug.Log(str);
    

    此时输出为:

    This post published on 2017-12-14 is about
    interpolated strings.

    内插表达式中使用 ?: 运算符

    因为 : 在内插表达式中用来指定格式,因此当使用 ?: 运算符时,必须定义在括号内。如下所示:

    System.Random random = new System.Random();
    for (int i = 0; i != 3; ++i)
    {
        Debug.Log($"Value is {(random.Next() % 2 == 1 ? "Odd" : "Even")}");
    }
    

    输出结果为:

    Even
    Odd
    Odd

    实现细节

    根据 $ 的实现方式的不同,编译器会选择用不同的方式实现字符串插值。

    string.Concat

    当插值的对象为类型为 string 时,编译器会选择使用 string.Concat

    如下代码:

    string name = "meziantou";
    string hello = $"Hello {name}!";
    

    编译器会将其转换为:

    string name = "meziantou";
    string hello = string.Concat("Hello ", name, "!");
    

    string.Format

    如果插值的对象为类型为非 string 时,编译器会选择使用 string.Format

    如下代码:

    DateTime now = DateTime.Now;
    string str = $"It is {now}";
    

    编译器会将其转换为:

    DateTime now = DateTime.Now;
    string str = string.Format("It is {0}", now);
    

    FormattableString

    如果插值的对象为类型为 Formattable String 时,编译器会选择使用 FormattableStringFactory.Create 创建一个新的 FormattableString

    如下代码:

    object value1 = "Foo";
    object value2 = "Bar";
    FormattableString str = $"Test {value1} {value2}";
    

    编译器会将其转换为:

    object value1 = "Foo";
    object value2 = "Bar";
    FormattableString str = FormattableStringFactory.Create("Test {0} {1}", new object[] { value1, value2 });
    

    当真正需要使用该 string 时,会调用 FormattableString.ToString 方法,将其转换为 string。

    constants(C# 10)

    在 C# 10 中,支持将内插表达式的结果作为常量。如下所示:

    const string Username = "meziantou";
    const string Hello = $"Hello {Username}!";
    
    // In previous C# version, you need to use the following concat syntax
    const string Hello2 = "Hello " + Username + "!";
    

    Interpolated string handlers(C# 10)

    C# 10 中针对高性能场景,引入了 InterpolatedStringHandlerArgument,具体见:
    String Interpolation in C# 10 and .NET 6 - .NET Blog (microsoft.com)

    Reference

    $ - string interpolation - C# reference | Microsoft Docs

    String interpolation - C# tutorial | Microsoft Docs

    String interpolation in C# | Microsoft Docs

    Interpolated strings: advanced usages - Meziantou’s blog

    到此这篇关于C# $字符串插值的使用的文章就介绍到这了,更多相关C# $字符串插值内容请搜索就爱读以前的文章或继续浏览下面的相关文章希望大家以后多多支持就爱读!

    您可能感兴趣的文章:

    • C#利用插值字符串处理器写一个sscanf
    • 在 C# 中使用 插值字符串

    如何在Python Pandas中实现高效的模糊匹配和字符串搜索?

    fuzzywuzzy在Pandas中用apply变慢,因其纯Python实现且apply逐行调用、无法向量化;默认process.extractOne还需遍历全部候选,导致万行以上CPU明显卡顿。 为什么fuzzywuzzy在Pandas中直接用apply会变慢? 因为fuzzywuzzy(现为rapidfuzz)的每个字符串比对都是纯Python实现,apply会逐行调用、无法向量化,数据量一过...

    怎么优化Python中的字符串拼接操作以避免频繁的内存分配?

    +拼接在循环中特别慢,因字符串不可变,每次s=s+item都新建对象并复制全部内容,时间复杂度达O(n²),引发大量内存分配与垃圾回收;推荐用list.append()+''.join()降至O(n)。 为什么+拼接字符串在循环里特别慢? Python中的字符串是不可变对象,每次用+拼接都会创建新字符串并复制全部内容。在循环中反复执行s=s+item,时间复杂度是O(n²),且会触发大量临时内存分...

    Python中如何安全地执行动态字符串代码_使用ast.literal_eval代替eval

    不能直接用eval,因为它会执行任意Python表达式,包括危险操作如os.system;ast.literal_eval仅安全解析str、int、list等无副作用字面量,不支持函数调用或运算符,且对语法格式极其严格。 为什么不能直接用eval 因为eval会执行任意Python表达式,包括调用函数、访问全局变量、甚至执行os.system("rm-rf/")这类危险操作。哪怕输入看起来“只是个...

    时序预处理在Python里怎么解决频率不一致_应用Pandas的resample与样条插值对齐

    resample不能直接解决频率不一致问题,因为它仅适用于已有规则频率的DatetimeIndex,对不规则时间戳会报错或静默丢弃;正确做法是先set_index+asfreq生成规则索引再插值。 resample为什么不能直接解决频率不一致问题 resample看似是时序对齐的首选,但它只适用于已有规则频率(如'D'、'H')的DatetimeIndex。如果原始数据本身没有固定频率(比如时间戳...

    怎样在Python中将二进制数据转换为十六进制字符串?

    推荐使用bytes.hex():Python3.5+原生方法,语义清晰、性能好,返回小写十六进制字符串;binascii.hexlify()返回bytes需decode,已非首选;注意输入必须为bytes类型,字符串需先用bytes.fromhex()解析。 直接用binascii.hexlify()或bytes.hex(),后者更推荐——Python3.5+原生支持,无需导入,语义清晰,性能也好...

    如何在Python中移除字符串首尾的指定字符_使用strip、lstrip或rstrip

    strip()只清理字符串首尾指定字符,不处理中间部分,参数为字符集合而非子串;lstrip()和rstrip()分别专用于左端和右端清理;默认无参时移除所有Unicode空白字符。 strip为什么没去掉中间的字符 strip()只处理字符串首尾,完全不碰中间部分。这是它和replace()的根本区别——很多人试了"aabbccaa".strip("a")得到"bbcc"就以为“成功了”,但一旦...

    如何在不使用正则表达式的情况下按关键词“shiftdate”分割字符串

    本文介绍一种纯Python内置方法,无需导入re模块,即可将长字符串按指定关键词(如"shiftdate")切分为多个子串,并确保每个子串以该关键词开头。核心思路是利用str.split()配合字符串拼接,精准保留分隔符。 本文介绍一种纯python内置方法,无需导入`re`模块,即可将长字符串按指定关键词(如"shiftdate")切分为多个子串,并确保每个子串以该关键词开头。核心思路是利用`s...

    如何将十六进制字符串安全转换为对应字符(ASCII)

    本文详解如何将形如"48656c6c6f"的十六进制字符串正确解析为ASCII字符串,避免int()与chr()组合使用时因类型错误导致的崩溃,并推荐简洁、健壮的标准库方案。 本文详解如何将形如"48656c6c6f"的十六进制字符串正确解析为ascii字符串,避免`int()`与`chr()`组合使用时因类型错误导致的崩溃,并推荐简洁、健壮的标准库方案。 你遇到的错误:TypeError:'st...