Object.GetHashCode()的默认实现?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (12)

GetHashCode()工作的默认实现如何?它是否有效且足够好地处理结构,类,数组等等?

我试图决定在什么情况下我应该自己打包,在哪些情况下我可以安全地依靠默认实施来做好。

提问于
用户回答回答于
namespace System {
    public class Object {
        [MethodImpl(MethodImplOptions.InternalCall)]
        internal static extern int InternalGetHashCode(object obj);

        public virtual int GetHashCode() {
            return InternalGetHashCode(this);
        }
    }
}

InternalGetHashCode映射到对象本机::GetHashCode函数在CLR中,该函数如下所示:

FCIMPL1(INT32, ObjectNative::GetHashCode, Object* obj) {  
    CONTRACTL  
    {  
        THROWS;  
        DISABLED(GC_NOTRIGGER);  
        INJECT_FAULT(FCThrow(kOutOfMemoryException););  
        MODE_COOPERATIVE;  
        SO_TOLERANT;  
    }  
    CONTRACTL_END;  

    VALIDATEOBJECTREF(obj);  

    DWORD idx = 0;  

    if (obj == 0)  
        return 0;  

    OBJECTREF objRef(obj);  

    HELPER_METHOD_FRAME_BEGIN_RET_1(objRef);        // Set up a frame  

    idx = GetHashCodeEx(OBJECTREFToObject(objRef));  

    HELPER_METHOD_FRAME_END();  

    return idx;  
}  
FCIMPLEND

全面实施GetHashCodeEx相当大,所以更容易链接到C++源代码

用户回答回答于

对于一个类来说,默认值本质上是参考平等,通常很好。如果编写一个结构,覆盖相等(更重要的是为了避免装箱)更为常见,但无论如何你都要写一个结构非常罕见!

当重写等式,你应该始终有一个匹配的Equals()GetHashCode()(即两个值,如果Equals()返回true,他们必须返回相同的哈希码,但反过来不是必需的) -这是常见的也提供==/ !=运营商,并经常到也执行IEquatable<T>

为了生成散列码,通常使用分解总和,因为这样可以避免配对值的冲突 - 例如,对于基本的2场散列:

unchecked // disable overflow, for the unlikely possibility that you
{         // are compiling with overflow-checking enabled
    int hash = 27;
    hash = (13 * hash) + field1.GetHashCode();
    hash = (13 * hash) + field2.GetHashCode();
    return hash;
}

这具有以下优点:

  • {1,2}的散列与{2,1}的散列不同
  • {1,1}的散列与{2,2}的散列不同

等 - 如果只使用未加权的总和或xor(^)等,这可能是常见的。

扫码关注云+社区