为何从byte数组转换的bool HashSet未去重,仍保留3个元素?
问题:为何从byte数组构造HashSet时会保留重复值?
我大致了解相关情况,但需要具体的原理解释:当我使用源自byte数组的数据构造HashSet
byte[] bytes = new byte[] { 0, 1, 2 }; ReadOnlySpan<byte> span = new(bytes); ReadOnlySpan<bool> boolSpan = MemoryMarshal.Cast<byte, bool>(span); bool[] bools = boolSpan.ToArray(); Console.WriteLine(string.Join(", ", bools)); // 输出:False, True, True Console.WriteLine(new HashSet<bool>(bools).Count); // 输出:3?? Console.WriteLine(string.Join(", ", new HashSet<bool>(bools))); // 输出:False, True, True
原理分析
核心原因在于非规范的bool实例与HashSet的判断逻辑冲突:
bool的底层存储规范与强制转换的特殊性
.NET中bool类型的官方规范是:false对应字节0x00,true对应字节0x01。但通过MemoryMarshal.Cast<byte, bool>直接操作内存的方式,可以创建出底层字节为非0非1的bool实例(比如示例中byte=2转成的bool,底层是0x02)。ToString的逻辑判断
当调用bool.ToString()时,逻辑是"非0即True",所以不管底层是0x01还是0x02,都会输出True,这就造成了视觉上的"重复值",但它们的底层存储并不相同。HashSet的元素重复判断逻辑
HashSet判断元素是否重复时,会先比较哈希码(GetHashCode()),只有哈希码相同才会进一步调用Equals()验证:- 对于bool的
Equals()方法:是逻辑相等判断,只要两个bool的底层值都是非0(或都是0),就会返回true。 - 但bool的
GetHashCode()方法:在.NET的多数实现中,是直接基于底层字节值计算哈希码,而非统一返回1表示true。
这就导致了矛盾:示例中两个"视觉上的True",底层分别是
0x01和0x02,它们的哈希码分别为1和2——HashSet看到哈希码不同,就直接判定为不同元素,不会再调用Equals(),所以这两个"True"会被同时保留在HashSet中。- 对于bool的
内容的提问来源于stack exchange,提问作者Drago Rosson
相关产品推荐
相关产品推荐

