C# 字符串与集合核心知识梳理
一、思维导图以下是本文内容的整体知识脉络使用 XMind 绘制思维导图详解1. string 类基础sealed / char[] / 不可变 / .Lengthstring 是 C# 中最常用的类型之一但它有几个关键特性**sealed 修饰意味着不能被继承**保证了字符串行为的统一性**底层是一个 char[] 字符数组**通过 .Length 获取字符个数。最重要的一点——**字符串不可变**任何对字符串的修改操作如替换、拼接实际上都会创建一个全新的字符串对象原字符串保持不变。这带来了线程安全和字符串驻留的优势但也意味着频繁拼接会有性能开销。2. 查找IndexOf / LastIndexOf-1IndexOf 查找子串或字符**首次出现的位置**LastIndexOf 查找**最后一次出现的位置**两者都**区分大小写**。如果未找到目标内容统一返回 **-1**这是判断是否包含指定内容的标准方式。3. 截取判断Substring / StartsWith / EndsWith / IsNullOrEmptySubstring 用于截取子字符串指定起始索引和长度。StartsWith / EndsWith 分别判断字符串是否以指定内容**开头**或**结尾**返回 bool常用于文件扩展名校验、URL 前缀判断等场景。IsNullOrEmpty 是静态方法用于同时判断字符串是否为 null 或空字符串 是防御性编程的常用手段。4. 大小写转换ToUpper / ToLower → 验证码ToUpper 转大写、ToLower 转小写。一个经典应用场景是**验证码校验**将用户输入和正确答案统一转为大写或小写后再比较实现忽略大小写的匹配。5. 其他操作Split / Replace / Trim / ToCharArray- **Split**按指定分隔符将字符串拆分为 string[]常用于解析 CSV、日志行等格式化文本。- **Replace**替换指定内容返回新字符串**原字符串不变**不可变性的体现。- **Trim**去除首尾空白字符空格、制表符、换行等常用于清洗用户输入。- **ToCharArray**将字符串转换为 char[]便于逐字符处理。6. StringBuilderAppend / Insert / Remove当需要频繁拼接字符串时直接用 会不断创建新对象性能极差。StringBuilder 内部维护一个**可变的字符缓冲区**- **Append**在末尾追加内容。- **Insert**在指定位置插入内容。- **Remove**删除指定范围的字符。最终通过 ToString() 一次性生成字符串大幅减少内存分配。7. LINQ 枚举GetEnumerator → foreachLINQLanguage Integrated Query提供了一套针对集合和序列的**声明式查询语法**如 Where、Select、OrderBy 等让数据筛选和转换变得简洁优雅。GetEnumerator 返回枚举器是实现 foreach 遍历的底层机制——任何实现了 IEnumerable 的类型都可以用 foreach 直接遍历。8. 异常处理try-catch / throwtry-catch 用于**捕获并处理异常**防止程序崩溃。throw 用于**主动抛出异常**向调用方传递错误信息。两者配合构成 C# 的异常处理体系是编写健壮程序的基础。9. 集合类型数组 / LinkedList / Hashtable- **数组**定长、连续内存分配索引访问速度最快 O(1)。- **链表 LinkedList**节点通过指针连接增删操作 O(1) 无需移动元素适合频繁插入删除的场景。- **哈希表 Hashtable**基于哈希算法实现键值对存储查找、插入、删除均为近似 O(1)。10. HashSet Dictionary不重复 / 键值对- **HashSet**无序集合**元素不可重复**常用于去重和集合运算交集、并集、差集。- **Dictionary**无序的键值对集合**Key 不允许重复Value 允许重复**。通过 Key 查找 Value 为 O(1)是替代多重 if-else 或 switch 的优雅方案。11. 委托方法作类型 / 匿名 → Lambda**委托**是将方法当作数据类型来传递的机制本质上是一个指向方法的类型安全的指针。从具名方法 → 匿名方法 → Lambda 表达式语法逐步精简// 具名方法Funcint, int, int add Add;// 匿名方法Funcint, int, int add delegate(int a, int b) { return a b; };// LambdaFuncint, int, int add (a, b) a b;委托是事件驱动、回调函数、LINQ 表达式的基石。12. DateTimeDateTime.NowDateTime.Now 获取当前系统时间对象包含年、月、日、时、分、秒等属性。常用于日志记录、计时、定时任务等场景。二、最近遇到的问题与解题思路问题大批量字符串拼接导致内存暴涨在做一个日志分析工具时需要对几十万行文本进行拼接输出最初代码直接使用 拼接string result ;foreach (var line in lines){result line \n; // 每次循环生成新字符串对象}结果程序运行非常慢内存持续飙升。排查后发现**string 是不可变的每次 都会在堆上分配一个新字符串对象**几十万次循环就产生了海量垃圾对象GC 频繁触发CPU 和内存双双吃紧。解题思路1. **找准根因**string 的不可变性是设计使然线程安全、字符串驻留池等优势但在频繁拼接场景下恰恰是性能杀手。2. 选择合适工具——StringBuilderStringBuilder sb new StringBuilder();foreach (var line in lines){sb.Append(line).Append(\n);}string result sb.ToString();StringBuilder 内部维护一个可变的 char[] 缓冲区Append 直接在缓冲区末尾写入无需每次分配新对象性能提升数十倍。3. 延伸思考- 少量固定拼接5 次用 即可编译器会优化为 string.Concat- 循环拼接、条件拼接 → 必须用 StringBuilder- 分隔符拼接直接用 string.Join 更简洁底层同样是高效实现 一句话总结理解 string 底层是 char[] 且不可变才能在合适的场景选用 StringBuilder、string.Join 等正确的工具避免字符串拼接成为性能瓶颈。