3. String字符串深度操作
讲真,绝大多数写C#的人,这辈子都没真正理解过 string 到底是个什么玩意儿。
你可能觉得,字符串嘛,就是个字符集合。你定义了 string name = "张三";,然后修改一下 name += "李四";,满以为这叫“追加”。但如果你在论坛上这么写,等着被那个秃顶的老法师或者是更年轻但刚入职的代码审查员把你的代码全骂一遍吧。
咱们今天不搞虚的,就聊聊 string 背后的那些坑,以及怎么优雅地填坑。
1. 引用类型的“伪善”与不可变性
很多初学者容易把 string 搞成 struct,这就是典型的“假小子装淑女”。
虽然你在写代码时感觉它在像基本类型一样变化,比如操作、拼接,但在底层的 .NET 机制里,string 实际上是个 引用类型。
最核心的坑叫 不可变性。
想象一下,你手里有一张写着 "Hello" 的纸。你想改成 "Hello World",你没法直接在纸上涂改,你只能撕掉这张旧纸,拿一张新的,重新写上 "Hello World"。那张旧纸 "Hello" 还在垃圾桶里,但它不再属于你了。
代码里的表现:
string str1 = "Hello";
string str2 = str1;
str2 = str2 + " World";
Console.WriteLine(object.ReferenceEquals(str1, str2)); // 输出: False
当你对 str2 进行修改时,内存里瞬间生成了一个新的字符串对象。str1 和 str2 指向完全不同的两块地方,哪怕它们的内容长得一模一样。
千万不要觉得这是累赘,这是安全机制。 在多线程环境下,不可变性意味着谁都不用担心别人随手改了你的数据。只要心里有数就行。
2. 循环拼接是个坏习惯
这是新手最容易触发的“内存炸弹”。
如果你在一个 for 循环里几百次地拼接字符串,就像是在用一次性筷子堆城堡。
// 致命的写法
string result = "";
for (int i = 0; i < 10000; i++)
{
result += i.ToString();
}
这不仅仅是慢的问题,更严重的后果是 GC(垃圾回收器)会累死。每次 +=,内存里都会扔下 10,000 个没用的碎片,程序跑着跑着就卡顿,那叫一个“卡成狗”。
正确的姿势是 StringBuilder。
它就像个随身带的笔记本,写错了一页撕掉重写,而不是每写一笔都去纸上涂改。它能在内存里预留一块连续空间,只生成一个最终的对象。
// 神仙写法
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.Append(i);
}
string result = sb.ToString();
虽然 StringBuilder 是引用类型,但在这种场景下,它的行为更像是在“累积”数据,而不是制造垃圾。
3. 字符串插值与格式化:别再玩 String.Format 了
早几年的代码里,你肯定见过这种反人类的写法:
string msg = String.Format("用户 {0} 在 {1} 点登录了系统", user.Name, DateTime.Now);
那是什么年代了?谁还要数 {0}?数数字容易数错,还要记顺序。
C# 给了你个糖:字符串插值 ($)。
// 写得像人话一样
string msg = $"用户 {user.Name} 在 {DateTime.Now} 点登录了系统";
这种写法是编译器在帮你干苦力。它在编译阶段自动把变量塞进了模板里。这不仅写起来快,读起来也爽。遇到复杂的格式化需求,直接在花括号里写表达式:
Console.WriteLine($"价格是 {price:C},折后只需 {price * 0.8:C}");
这行代码直接把你扔进了一个格式化的魔法森林里。C 代表货币格式,P 代表百分比。如果你懂正则或者 IFormatProvider,你甚至能在这里面写逻辑。
4. 空值处理:别让 NullReferenceException 送你走人
在这个充满不确定性的世界里,变量“空着”是最常见的事。
最傻的检查方式是写个连乘:
if (str != null && str.Length > 0) { ... }
很多新人是这样写的,因为书上这么教。但这种方式在 str 为 null 的时候,第一个判断就停了,虽然安全,但写起来像绕口令。
现代 C# 告诉你,反着写更帅。
if (!string.IsNullOrEmpty(str)) { ... }
或者更狠一点,现在很多老手直接在参数定义里就搞事情:
public void ProcessData(string? input)
那个问号 ? 表示 input 可以是 null。编译器会逼迫你在使用它之前做判断。这叫“防御性编程”,不是胆小,是怕死。
5. 总结与避坑
操作字符串,记住这三条铁律:
- 想改就重写,别想原地涂改:理解不可变性,搞清楚引用和内容的区别。
- 循环拼接用
StringBuilder:如果你在一个循环里拼字符串,除非是那种极小的次数(比如拼接三次),否则默认用StringBuilder,别跟垃圾回收器过不去。 - 优先用
$和IsNullOrEmpty:让代码读起来像散文,而不是乱码。
最后送你一句大实话:
代码是写给人看的,顺便给机器运行。如果你在 string 的操作上写了一堆让人费解的 Format 和 + 号,那不仅仅是你的技术问题,更是对阅读你代码的人的一种精神折磨。
写代码吧,趁早把那些反人类的写法都扔进垃圾桶里。





这一切,似未曾拥有