在GetHashCode函数中创建对象是个坏主意吗
本文关键字:GetHashCode 函数 创建对象 | 更新日期: 2023-09-27 18:20:24
我有一个基类MyBase
和大约十几个派生类。我在代码中严重依赖访问者模式。因此,基类是访问者的抽象宿主,每个派生类都是具体宿主。我正在使用一个独立的比较器来实现IEqualityComparer<MyBase>
接口。该接口中有两种方法:Boolean Equals(MyBase a, MyBase b)
和Int32 GetHashCode(MyBase obj)
。在这些方法中,我使用一个访问者将MyBase
的实例解析为派生类型之一的实例。这就是我避免处理选角的方法。因此,访问者是每次调用Equals
和GetHashCode
时都需要创建的对象。我读了很多关于保持GetHashCode
尽可能便宜的文章,所以问题是:
考虑到性能,在GetHashCode
和Equals
方法中创建对象(访问者)是个坏主意吗?
这个问题假定创建一个新对象的成本很高。事实并非如此。创建一个新对象需要将堆指针向上移动对象的大小,将这些字节清零,然后调用构造函数。只要构造函数不做任何昂贵的事情,并且有足够的内存用于分配(如果没有,GC需要运行,这是而不是便宜的),这将非常快。
与创建新对象相关的"成本"是在需要收集新对象时产生的。创建更多的对象意味着你需要更频繁地收集垃圾,所以在未来某个不确定的时刻,你会放慢代码的速度。话虽如此,除非你正在创建很多对象,或者非常大的对象,并且这些对象的寿命不长,否则这应该根本不是问题。
GetHashCode()
的实现应该以这样一种方式编写,即第一个调用之后的每个调用都会很快。如果计算一个对象的哈希值需要构造一个新对象,那么这是一个很好的迹象,表明该对象可能应该在计算一次哈希值后缓存该哈希值,这样以后对哈希代码的请求就可以快速得到响应。请注意,使用标志来指示是否已经计算了哈希代码可能是不值得的;相反,决定零不是有效的哈希代码值,并有一个HashCode
字段,该字段被初始化为零,但一旦计算完毕,就会被哈希代码覆盖。如果哈希代码的计算方法将产生零,请替换其他任意值。零和另一个值都应该只出现在大约4000000000的时间内,所以将另一个数值翻倍到1/20000000000的概率应该没什么大不了的。
如果您正在缓存哈希代码,那么它们的计算是否有点昂贵也不重要,因为它只会完成一次。即使缓存了哈希代码,也应该尽量使其速度合理,但不要太担心。