最简洁方式是str?.Count(c => c == 'a') ?? 0,需判空防NullReferenceException;性能敏感时用foreach遍历,零分配、无装箱、兼容.NET Framework 2.0+。

用 Count() 最简洁,但要注意字符串为空或 null
直接调用 string.Count(c => c == targetChar) 是最直观的方式,底层走的是 LINQ,可读性好。但必须提前判空,否则 null 字符串会抛出 NullReferenceException;空字符串则安全返回 0。
- 推荐写法:
int count = str?.Count(c => c == 'a') ?? 0;
- 避免写法:
str.Count(...)(没判 null)或str.Where(...).Count()(多一次枚举) - 注意:LINQ 的
Count()对字符串是 O(n),无性能陷阱,但若在高频循环里反复调用,建议缓存结果
用 foreach 手动遍历,兼容 .NET Framework 2.0+ 且零分配
不依赖 LINQ 时,foreach 遍历字符数组是最轻量、最可控的方式,无装箱、无迭代器开销,适合性能敏感或老项目。
- 典型写法:
int count = 0;<br>foreach (char c in str)<br>{<br> if (c == 'x') count++;<br>} - 别写
for (int i = 0; i 然后取str[i]—— 虽然等效,但不如foreach语义清晰且 JIT 优化更好 - 注意:
str为null时会抛NullReferenceException,务必前置检查
区分大小写?别默认用 IndexOf() 循环找
有人用 IndexOf() 配合循环统计,初衷是想支持忽略大小写的搜索,但这是个误区:它既难读又易错,且比直接遍历慢。
- 错误示范:
while ((i = str.IndexOf('a', i, StringComparison.OrdinalIgnoreCase)) != -1) { i++; count++; }—— 容易漏字符、越界、逻辑混乱 - 正确做法:先转统一大小写再遍历,或用
char.ToLower(c) == char.ToLower(target)判断 - 如果真要忽略文化差异(比如土耳其语的 I/i),必须用
char.ToUpperInvariant(c) == char.ToUpperInvariant(target),而非ToLowerCase
统计 Unicode 标量值?别把代理对当两个字符
普通 foreach (char c in str) 按 UTF-16 code unit 遍历,对 ?(U+1F680)这类超出 BMP 的字符,会拆成两个 char(即代理对)。若需按真实“字符”(Unicode 标量值)计数,不能直接比 char。
- 场景举例:统计 emoji 或某些中文古字时,发现数量翻倍或匹配不上
- 解决方式:用
Rune.DecodeFromUtf16()(.NET Core 3.0+)或StringInfo.GetTextElementEnumerator()(全版本兼容) - 简单替代(仅限确认无代理对时):
str.AsSpan().Length是 code unit 数,不是字符数
实际用哪个方法,取决于你是否需要文化感知、是否运行在旧框架、以及是否处理 emoji 类字符——这些细节不提前想清楚,后期 debug 会卡很久。











