You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何SortedDictionary添加不同字符串键报错而Dictionary正常?

问题原因分析

这背后的核心是Unicode字符的两种表示形式差异,以及.NET中Dictionary和SortedDictionary默认采用的键比较规则不同导致的:

1. 两个字符串的本质差异

你看到的两个字符串视觉上完全一致,但它们的Unicode编码其实不一样:

  • filename1里的é是拆分字符组合:由字母e(编码101)加上组合重音符´(编码769,U+0301)两个字符组成
  • filename2里的é是预组合字符:单个Unicode字符é(编码233,U+00E9)

2. 两种字典的比较规则差异

Dictionary<string, int>的判断逻辑

Dictionary默认使用EqualityComparer<string>.Default,也就是基于字节序列的序数(Ordinal)比较。它会严格检查字符串的每个字符编码是否完全一致,因为两个字符串的字节序列不同,所以Dictionary认为是两个不同的键,自然可以正常添加。

你可以用下面的代码验证这一点:

// 返回 false,说明序数比较下两个字符串不相等
bool ordinalEqual = string.Equals(filename1, filename2, StringComparison.Ordinal);

SortedDictionary<string, int>的判断逻辑

SortedDictionary默认使用Comparer<string>.Default,也就是基于当前系统文化的排序比较。在绝大多数文化(比如法语、英语文化)中,Unicode的拆分组合字符和预组合字符会被视为语义等价的——简单说就是排序时认为它们是同一个字符。所以当你添加第二个键时,SortedDictionary判定这是重复键,抛出ArgumentException。

同样可以用代码验证:

// 返回 true,说明文化敏感比较下两个字符串被视为相等
bool cultureEqual = string.Equals(filename1, filename2, StringComparison.CurrentCulture);

解决方案

如果希望SortedDictionary也像Dictionary那样严格按字符编码判断键是否相等,可以在初始化时指定序数比较器:

// 指定StringComparer.Ordinal,按字节序列严格比较
var files2 = new SortedDictionary<string, int>(StringComparer.Ordinal);
files2.Add(filename1, 1);
files2.Add(filename2, 2); // 现在可以正常执行,不会抛出异常

内容的提问来源于stack exchange,提问作者A.Baudouin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:12:03