Skip to content

C# - 字符串

在 C# 中,string 是一系列字符,用于表示文本。它是 System.String 类的别名。字符串是任何应用程序中最基本和最常用的类型之一。C# 字符串的一个关键特性是它们是不可变的(immutable):一旦创建了字符串对象,它的值就不能更改。任何看似修改字符串的操作实际上都会创建一个新的字符串对象。

你可以通过多种方式创建字符串,但最常见的是使用字面量(literals)和字符串插值(string interpolation)。

using System;
using System.Text;
// 1. 使用字符串字面量
var greeting = "Hello, World!";
// 2. 字符串插值(现代、推荐的格式化方式)
var user = "Alice";
var score = 120;
var welcomeMessage = $"Welcome, {user}! Your score is {score}.";
// 3. 逐字字符串字面量(用于路径、多行文本)
var filePath = @"C:\Users\Default\Documents";
var multiLine = @"This is a string
that spans multiple
lines.";
// 4. 原始字符串字面量 (C# 11+, 用于 JSON, XML 等)
var json = """
{
"name": "Bob",
"score": 95
}
""";
Console.WriteLine(greeting);
Console.WriteLine(welcomeMessage);
Console.WriteLine(filePath);

string 类提供了一组丰富的用于操作的方法和属性。

using System;
var text = " Modern C# Programming ";
// 获取长度
Console.WriteLine($"Length: {text.Length}"); // 输出: 25
// 改变大小写
Console.WriteLine($"Uppercase: {text.ToUpper()}");
Console.WriteLine($"Lowercase: {text.ToLower()}");
// 去除空白字符
var trimmedText = text.Trim();
Console.WriteLine($"Trimmed: '{trimmedText}'"); // 输出: 'Modern C# Programming'
// 子字符串和范围 (C# 8+)
var language = trimmedText.Substring(7, 2); // (起始索引, 长度)
var modernWay = trimmedText[7..9]; // 使用 Range 运算符
Console.WriteLine($"Substring: {language}"); // 输出: C#
Console.WriteLine($"Range: {modernWay}"); // 输出: C#
// 搜索
bool containsCSharp = trimmedText.Contains("C#");
bool startsWithModern = trimmedText.StartsWith("Modern");
bool endsWithProgramming = trimmedText.EndsWith("Programming");
Console.WriteLine($"Contains 'C#': {containsCSharp}"); // 输出: True
// 替换
var newText = trimmedText.Replace("Modern", "Advanced");
Console.WriteLine($"Replaced: {newText}"); // 输出: Advanced C# Programming

正确地比较字符串至关重要。使用 == 会执行区分大小写的、序号式(逐字节)的比较。为了获得更多控制,特别是处理用户输入时,请使用 string.Equals 方法。

var str1 = "hello";
var str2 = "HELLO";
// 区分大小写的比较(结果为 false)
Console.WriteLine($"'hello' == 'HELLO': {str1 == str2}");
// 最佳实践:不区分大小写的比较
bool areEqual = string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"Are they equal (case-insensitive)?: {areEqual}");

最佳实践: 当比较来自不同源(如用户输入或外部 API)的字符串时,请务必指定 StringComparison 类型,以避免与文化和大小写敏感性相关的细微错误。OrdinalIgnoreCase 通常是非语言比较最安全、性能最佳的选择。

在 C# 中,字符串可以是 null、空字符串 (""),或者只包含空白字符。string.IsNullOrWhiteSpace 方法是检查这些状态中最健壮的方式。

string? input1 = null;
string input2 = "";
string input3 = " ";
string input4 = "some text";
Console.WriteLine($"Input 1 is null or whitespace: {string.IsNullOrWhiteSpace(input1)}"); // True
Console.WriteLine($"Input 2 is null or whitespace: {string.IsNullOrWhiteSpace(input2)}"); // True
Console.WriteLine($"Input 3 is null or whitespace: {string.IsNullOrWhiteSpace(input3)}"); // True
Console.WriteLine($"Input 4 is null or whitespace: {string.IsNullOrWhiteSpace(input4)}"); // False

由于字符串是不可变的,在循环中重复连接它们效率非常低。每次连接都会创建一个新的字符串对象,导致高内存分配和垃圾回收压力。为了以编程方式构建字符串,尤其是在循环中,请始终使用 System.Text.StringBuilder 类。

using System.Text;
// 低效方式 - 避免在循环中使用
string numbersStr = "";
for (int i = 1; i <= 5; i++) {
numbersStr += i.ToString() + " "; // 创建 5 个新的字符串对象
}
// 高效方式 - 使用 StringBuilder
var sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.Append(i).Append(' '); // 修改内部缓冲区
}
string result = sb.ToString(); // 只创建最终字符串一次
Console.WriteLine($"Inefficient result: {numbersStr}");
Console.WriteLine($"Efficient result: {result}");

String.Join 是一种从字符串集合构造单个字符串的高效方式。Split 则执行相反的操作。

// 连接
var items = new[] { "Apples", "Oranges", "Bananas" };
var csv = string.Join(", ", items);
Console.WriteLine($"CSV: {csv}"); // 输出: CSV: Apples, Oranges, Bananas
// 分割
var tags = "c#,dotnet,programming";
string[] tagArray = tags.Split(',');
Console.WriteLine("Tags found:");
foreach (var tag in tagArray)
{
Console.WriteLine($"- {tag}");
}