searchvalues并非万能多关键词搜索工具,仅在.net 9支持多字符匹配、.net 8限于单字符优化;误用类型或参数会导致编译失败或性能下降,必须配合span使用且需缓存实例。

SearchValues 和 SearchValues 的根本区别
SearchValues<char></char> 是 .NET 8 就支持的,专为单字符查找优化;SearchValues<string></string> 是 .NET 9 才加入的(2025 年底起可用),才支持子域名、路径片段这类多字符模式匹配。
常见错误:在 .NET 8 项目里写 SearchValues.Create(new[] { ".com", ".org" }),编译直接失败——SearchValues.Create 根本不接受 string[],除非你已升级到 .NET 9。
- .NET 8 只认
ReadOnlySpan<char></char>或ReadOnlySpan<byte></byte>,比如" \t\n\r"或new byte[] { 0x09, 0x0A, 0x0D, 0x20 } - .NET 9 新增
SearchValues.Create(string[])和SearchValues.Create(ReadOnlySpan<string>)</string>,但内部仍是基于前缀哈希 + 回退机制,不是 KMP 或 Aho-Corasick - 跨版本误用会导致编译报错或运行时
NotSupportedException,别靠“试试看”验证
为什么 SearchValues.Create("abc") 比 new char[] { 'a', 'b', 'c' } 快
关键不在“创建”,而在“复用”和“位图特化”。SearchValues.Create 对 ASCII 字符集(U+0000–U+007F)自动启用 128-bit 位图,IndexOfAny 变成一次位运算 + 条件跳转,O(1);而传数组会触发泛型重载,走线性扫描路径。
- 含重复字符会抛
ArgumentException,比如SearchValues.Create("aaab")→ 实际只收'a'和'b',但构造时就崩 - 含非 ASCII 字符(如
"αβγ")会降级为哈希表,仍比Contains快,但失去位图优势 - 空字符串或
null直接抛ArgumentNullException,别等上线后才发现
必须配合 Span 才零分配:IndexOfAny 才认 SearchValues
SearchValues 只被 ReadOnlySpan<t>.IndexOfAny</t>、IndexOfAnyExcept、LastIndexOfAny 这三个方法识别。一旦调用 ToString()、Substring()、AsMemory(),就脱离 Span 上下文,底层优化完全失效。
- 正确写法:
text.AsSpan().IndexOfAny(s_separators),其中s_separators是static readonly SearchValues<char></char> - 错误写法:
text.IndexOfAny(s_separators)(string.IndexOfAny重载不接受SearchValues,编译不过) - 更隐蔽的错误:
text.AsSpan().ToArray().AsSpan().IndexOfAny(...)—— 看似用了 Span,实则中间分配了数组
CA1870 警告不是建议,是性能硬指标
分析器 CA1870 明确指出:对同一组值调用 IndexOfAny 超过 5 次,就必须缓存 SearchValues 实例。这不是风格问题,是避免每次调用都重建查找表的硬性要求。
- 静态字段必须是
static readonly,不能是局部变量或属性 getter - 不要在循环内反复
Create,哪怕只调用两次——初始化开销远高于查找本身 - 多线程安全:
SearchValues<t></t>实例是只读且线程安全的,可放心全局共享
最易忽略的一点:ContainsAny 和 ContainsAnyExcept 方法也认 SearchValues,但 Contains、IndexOf、Split 等完全无视它——别指望改个类型名就自动加速。











