我正在努力改进一段时间写的代码。该功能对系统的核心功能非常重要,因此我对大刀阔斧的改革持谨慎态度。
我正在使用字典来保存对象
Dictionary<Node, int> dConnections
对象Node
本身就是一个包含许多属性和一些列表的复杂对象。
这个字典可以变得非常大,可容纳100个或更多条目。
目前正在检查字典是否包含类似
的节点dConnections.ContainsKey(Node)
所以我假设(为了检查这个节点是否在字典中),字典必须检查整个节点及其属性是否与字典中的节点匹配(它将继续迭代字典,直到它找到匹配)这会对性能产生重大影响吗?
我最好不要在字典中使用对象而是使用对象ID。
答案 0 :(得分:5)
.NET字典是Inside中的哈希表。这意味着如果Node没有覆盖GetHashCode和Equals方法,当您调用ContainsKey时,它将匹配:
免责声明:这是一个总结。事情有点复杂。请不要叫我名字,因为我过于简单了。
此算法非常有效。如果你说字典中有100个或更多条目,那就不是“很多”了。这是一些。
这也意味着Node对象的内容与ContainsKey匹配的方式无关。它将与完全相同的引用匹配,并且仅针对此引用。
如果您自己实现GetHashCode和Equals,请注意当实例属性更改(不可变)时,这些方法返回值不应更改。否则你很可能在错误的存储桶中获取密钥,因此完全无法访问(无需枚举整个字典)。
答案 1 :(得分:3)
它将继续遍历字典,直到找到匹配
不,字典通过迭代所有节点找不到匹配项;首先获取哈希码,并用于将候选者限制为一个,可能是几个(取决于你的哈希方法有多好,以及桶大小)
所以我假设(为了检查这个节点是否在字典中),字典必须检查整个节点及其属性是否与字典中的节点匹配
不,对于每个候选人,它首先检查哈希码,这是一个快捷方式,以检测非 -equality vs 可能的 -equality非常快速
所以关键在于:您的Node
散列方法,即GetHashCode
。如果这很复杂,那么另一个技巧是在你第一次需要它时将其缓存,即
int cachedHashCode;
public override int GetHashCode() {
if(cachedHashCode == 0) {
cachedHashCode = /* some complex code here */
if(cachedHashCode == 0) {
cachedHashCode = -45; // why not... just something non-zero
}
}
return cachedHashCode;
}
请注意 仍然使用Equals
,因为最终“它们是相同的”,所以你显然希望Equals
尽可能快 - 但Equals
将被称为相对较少。