在C#字典中高效存储XYZ字节对的最优方法是什么?
问题分析与解决方案
第一种方式完全不可行
你贴的代码存在两个致命问题,根本没法正确实现需求:
- 哈希值不看内容:.NET里数组的默认
GetHashCode()是基于对象引用的,而非数组内的字节内容。哪怕两个byte[3]的XYZ完全一致,只要是新创建的数组实例,哈希值就不一样。这会导致相同的XYZ对应不同的Key,后续你根本查不到之前存入的对象。 - 冲突概率极高:就算忽略引用问题,
int类型的哈希空间有限,数万条数据很容易出现不同XYZ算出相同哈希的情况,要么覆盖已有数据,要么让Dictionary的性能暴跌。
第二种方式才是正确方向
用byte[3]当Key,再配合自定义相等比较器,能解决上面的所有问题:
- 可以基于XYZ的实际字节内容判断两个Key是否相等,确保相同的XYZ对应同一个Key;
- 可以自定义哈希计算逻辑,降低冲突概率,让Dictionary的存取效率保持最优。
具体实现示例
先写一个针对byte[3]的相等比较器:
public class Byte3EqualityComparer : IEqualityComparer<byte[]> { public bool Equals(byte[] x, byte[] y) { if (ReferenceEquals(x, y)) return true; if (x == null || y == null || x.Length != 3 || y.Length != 3) return false; return x[0] == y[0] && x[1] == y[1] && x[2] == y[2]; } public int GetHashCode(byte[] obj) { if (obj == null || obj.Length != 3) throw new ArgumentException("必须是长度为3的byte数组"); // 基于三个字节计算哈希,这里用简单的位运算组合,也可以用更复杂的算法进一步降低冲突 return obj[0] ^ (obj[1] << 8) ^ (obj[2] << 16); } }
然后创建Dictionary时传入这个比较器:
var table = new Dictionary<byte[], object>(new Byte3EqualityComparer()); // 添加元素 table.Add(new byte[] { x, y, z }, yourObject); // 查找元素 if (table.TryGetValue(new byte[] { x, y, z }, out var targetObj)) { // 处理找到的对象 }
更优的优化方案
如果想减少每次创建byte[3]实例的开销,建议把XYZ封装成一个值类型(struct):
public struct XyzKey { public byte X { get; } public byte Y { get; } public byte Z { get; } public XyzKey(byte x, byte y, byte z) { X = x; Y = y; Z = z; } public override bool Equals(object obj) { return obj is XyzKey key && Equals(key); } public bool Equals(XyzKey other) { return X == other.X && Y == other.Y && Z == other.Z; } public override int GetHashCode() { return X ^ (Y << 8) ^ (Z << 16); } }
用起来更简单,性能也更好:
var table = new Dictionary<XyzKey, object>(); table.Add(new XyzKey(x, y, z), yourObject);
值类型默认就是按内容比较相等性,不需要额外写比较器,代码更简洁,还避免了数组引用带来的问题,存取效率也更高。
内容的提问来源于stack exchange,提问作者user2980746
相关产品推荐
相关产品推荐

