在 C# 中:
csharp
string s = "Hello";
string 是 System.String 的别名:
csharp
System.String s = "Hello";
核心特性
-
string 是引用类型
-
string 是 sealed 密封类
-
底层存储为
char[] -
实现了:
IComparableIEnumerable<char>IEquatable<string>
二、字符串创建方式
1️⃣ 直接赋值(最常用)
csharp
string name = "Jack";
2️⃣ 使用构造函数
csharp
char[] chars = { 'H', 'e', 'l', 'l', 'o' };
string str = new string(chars);
3️⃣ 字符串拼接
csharp
string fullName = firstName + " " + lastName;
4️⃣ string.Join
csharp
string[] arr = { "A", "B", "C" };
string result = string.Join("-", arr);
5️⃣ 字符串插值(推荐)
csharp
string name = "Tom";
int age = 20;
string msg = $"Name: {name}, Age: {age}";
三、字符串不可变(核心理解)
csharp
string s = "Hello";
s += " World";
看似修改字符串,实际发生:
- 创建新字符串
"Hello World" - 原字符串保持不变
- 原对象等待 GC 回收
为什么设计为不可变?
- 线程安全
- 支持字符串常量池
- 哈希值稳定(可作为 Dictionary key)
- 提高 CLR 优化能力
四、字符串驻留机制(Intern 机制)
csharp
string s1 = "abc";
string s2 = "abc";
可能指向同一块内存。
因为:
- CLR 维护字符串常量池
- 相同字面量只存储一份
验证:
csharp
Console.WriteLine(object.ReferenceEquals(s1, s2));
五、字符串拼接性能对比
❌ 不推荐:循环中使用 +
csharp
string result = "";
for(int i = 0; i < 10000; i++)
{
result += i;
}
问题:
- 每次拼接都会创建新对象
- 产生大量 GC
✅ 推荐:StringBuilder
csharp
using System.Text;
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10000; i++)
{
sb.Append(i);
}
string result = sb.ToString();
特点:
- 可变字符串
- 性能高
- 减少内存分配
使用建议
| 场景 | 推荐方式 |
|---|---|
| 少量拼接 | + 或 $ |
| 多参数格式化 | 字符串插值 |
| 数组拼接 | string.Join |
| 循环拼接 | StringBuilder |
六、字符串常用属性
csharp
string text = "Hello";
| 成员 | 说明 |
|---|---|
| Length | 获取长度 |
| text[index] | 获取指定位置字符 |
示例:
csharp
Console.WriteLine(text.Length); // 5
Console.WriteLine(text[1]); // e
七、常用字符串方法
1️⃣ 比较字符串(推荐写法)
❌ 不推荐:
csharp
s1.ToLower() == s2.ToLower();
会创建新字符串。
✅ 推荐:
csharp
string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase);
常见枚举值:
| 枚举 | 说明 |
|---|---|
| Ordinal | 按字节比较 |
| OrdinalIgnoreCase | 忽略大小写 |
| CurrentCulture | 按当前文化比较 |
2️⃣ 判断是否包含
csharp
str.Contains("abc");
str.StartsWith("abc");
str.EndsWith("abc");
3️⃣ 查找位置
csharp
str.IndexOf("abc");
4️⃣ 截取
csharp
str.Substring(startIndex, length);
5️⃣ 替换
csharp
str.Replace("old", "new");
6️⃣ 分割
csharp
string[] parts = str.Split(',');
7️⃣ 去除空格
csharp
str.Trim();
str.TrimStart();
str.TrimEnd();
八、字符串判空(高频重点)
csharp
string.IsNullOrEmpty(str);
string.IsNullOrWhiteSpace(str);
区别:
| 方法 | 判断内容 |
|---|---|
| IsNullOrEmpty | null 或 "" |
| IsNullOrWhiteSpace | null、""、空格 |
推荐优先使用 IsNullOrWhiteSpace。
九、字符串格式化
1️⃣ string.Format
csharp
string result = string.Format("Name:{0}, Age:{1}", name, age);
2️⃣ ToString 格式化
csharp
DateTime dt = DateTime.Now;
string result = dt.ToString("yyyy-MM-dd HH:mm:ss");
3️⃣ 字符串插值(推荐)
csharp
string result = $"{dt:yyyy-MM-dd HH:mm:ss}";
十、DateTime 常见格式
csharp
DateTime dt = new DateTime(2024, 12, 25, 18, 45, 30, 256);
年
csharp
dt.ToString("yyyy"); // 2024
dt.ToString("yy"); // 24
月
csharp
dt.ToString("MM"); // 12
dt.ToString("MMMM"); // 十二月
日
csharp
dt.ToString("dd"); // 25
dt.ToString("dddd"); // 星期三
时间
csharp
dt.ToString("HH"); // 18
dt.ToString("mm"); // 45
dt.ToString("ss"); // 30
dt.ToString("fff"); // 256
十一、生产环境注意文化问题
csharp
using System.Globalization;
dt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
原因:
- 不同服务器地区文化不同
- 保证格式统一
- 避免线上问题
十二、== 与 Equals
对于 string:
csharp
string a = "abc";
string b = "abc";
Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True
string 重写了 ==,比较的是值,不是地址。
十三、常见面试总结点
- string 是引用类型
- string 是不可变类型
- 存在字符串常量池
- 频繁拼接使用 StringBuilder
- 比较字符串推荐使用 StringComparison
- 判空使用 IsNullOrEmpty / IsNullOrWhiteSpace
- 生产环境注意文化问题
- string 重写了 == 运算符
最终整体理解
掌握字符串不仅是会用 API,而是理解:
- 内存模型
- 不可变设计思想
- 性能差异
- 文化差异
- 实际生产环境写法
当你能够解释"为什么要这样写",而不仅仅是"怎么写",说明你已经真正掌握了 C# 字符串。