一.两个逻辑上相等的实例对象。

两个对象相等,除了指两个不同变量引用了同一个对象外,更多的是指逻辑上的相等。什么是逻辑上相等呢?就是在一定的前提上,这两个对象是相等的。比如说某男生叫刘益红,然后也有另外一个女生叫刘益红,虽然这两个人身高,爱好,甚至性别上都不相同,但是从名字上来说,两者是相同的。Equals方法通常指的就是逻辑上相等。

二.Object的GetHashcode方法。

计算Hashcode的算法中,应该至少包含一个实例字段。Object中由于没有有意义的实例字段,也对其派生类型的字段一无所知,因此就没有逻辑相等这一概念。所以默认情况下Object的GetHashcode方法的返回值,应该都是独一无二的。利用Object的GetHashcode方法的返回值,可以在AppDomain中唯一性的标识对象。

下面是.Net中Object代码的实现:


    [Serializable]
    public class Object
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public Object()
        {
        }
        public virtual string ToString()
        {
            return this.GetType().ToString();
        }
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public virtual bool Equals(object obj)
        {
            return RuntimeHelpers.Equals(this, obj);
        }
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool Equals(object objA, object objB)
        {
            return objA == objB || (objA != null && objB != null && objA.Equals(objB));
        }
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool ReferenceEquals(object objA, object objB)
        {
            return objA == objB;
        }
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public virtual int GetHashCode()
        {
            return RuntimeHelpers.GetHashCode(this);
        }
        [SecuritySafeCritical]
        [MethodImpl(MethodImplOptions.InternalCall)]
        public extern Type GetType();
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        protected virtual void Finalize()
        {
        }
        [SecuritySafeCritical]
        [MethodImpl(MethodImplOptions.InternalCall)]
        protected extern object MemberwiseClone();
        [SecurityCritical]
        private void FieldSetter(string typeName, string fieldName, object val)
        {
            FieldInfo fieldInfo = this.GetFieldInfo(typeName, fieldName);
            if (fieldInfo.IsInitOnly)
            {
                throw new FieldAccessException(Environment.GetResourceString("FieldAccess_InitOnly"));
            }
            Message.CoerceArg(val, fieldInfo.FieldType);
            fieldInfo.SetValue(this, val);
        }
        private void FieldGetter(string typeName, string fieldName, ref object val)
        {
            FieldInfo fieldInfo = this.GetFieldInfo(typeName, fieldName);
            val = fieldInfo.GetValue(this);
        }
        private FieldInfo GetFieldInfo(string typeName, string fieldName)
        {
            Type type = this.GetType();
            while (null != type && !type.FullName.Equals(typeName))
            {
                type = type.BaseType;
            }
            if (null == type)
            {
                throw new RemotingException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_BadType"), new object[]
                {
                    typeName
                }));
            }
            FieldInfo field = type.GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
            if (null == field)
            {
                throw new RemotingException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_BadField"), new object[]
                {
                    fieldName, 
                    typeName
                }));
            }
            return field;
        }
    }

 

 为什么会有Hashcode?

Hashcode是为了帮助计算出该对象在hashtable中所处的位置。而能够把一个对象放入hashtable中无疑是有好处的。

这是Hashcode的作用,但是我们为什么需要他?

因为一个类型在定义了Equals方法后,在System.Collections.Hashtable类型,System.Collections.Generic.Dictionary类型以及其他一些集合的实现中,要求如果两个对象相等,不能单单只看Equals方法返回true,还必须要有相同的Hashcode.

这相当于一种前提条件的假设,而上述这些类型就是基于这种假设的基础上实现的。如果不遵守这些条件,那么在使用这些集合的时候就会出问题。

下面是摘自MSDN的一段描述

Hashcode是一个用于在相等测试过程中标识对象的数值。它还可以作为一个集合中的对象的索引。 GetHashCode方法适用于哈希算法和诸如哈希表之类的数据结构。 GetHashCode 方法的默认实现不保证针对不同的对象返回唯一值。而且,.NET Framework 不保证 GetHashCode 方法的默认实现以及它所返回的值在不同版本的 .NET Framework 中是相同的。因此,在进行哈希运算时,该方法的默认实现不得用作唯一对象标识符。

上面这段话想说明的就是:两个对象相等,hashcode也应该相等。但是两个对象不等,hashcode也有可能相等。

下面这两个不同的string对象就产生了相同的hashcode:

            string str1 = "NB0903100006";
string str2 = "NB0904140001";
Console.WriteLine(str1.GetHashCode());
Console.WriteLine(str2.GetHashCode());

这是因为string类型重写了Object的GetHashcode方法,如下:


        public override int GetHashCode() {
            unsafe { 
                fixed (char *src = this) {
                    Contract.Assert(src[this.Length] == '\0'"src[this.Length] == '\\0'");
                    Contract.Assert( ((int)src)%4 == 0"Managed string should start at 4 bytes boundary");
 
#if WIN32
                    int hash1 = (5381<<16) + 5381
#else 
                    int hash1 = 5381;
#endif 
                    int hash2 = hash1;

#if WIN32
                    // 32bit machines. 
                    int* pint = (int *)src;
                    int len = this.Length; 
                    while(len > 0) { 
                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
                        if( len <= 2) { 
                            break;
                        }
                        hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
                        pint += 2
                        len  -= 4;
                    } 
#else 
                    int     c;
                    char *s = src; 
                    while ((c = s[0]) != 0) {
                        hash1 = ((hash1 << 5) + hash1) ^ c;
                        c = s[1];
                        if (c == 0
                            break;
                        hash2 = ((hash2 << 5) + hash2) ^ c; 
                        s += 2
                    }
#endif 
#if DEBUG
                    // We want to ensure we can change our hash function daily.
                    
// This is perfectly fine as long as you don't persist the
                    
// value from GetHashCode to disk or count on String A 
                    
// hashing before string B.  Those are bugs in your code.
                    hash1 ^= ThisAssembly.DailyBuildNumber; 
#endif 
                    return hash1 + (hash2 * 1566083941);
                } 
            }
        }

相关文章:

  • 2021-10-08
  • 2022-12-23
  • 2022-02-04
  • 2021-12-01
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2020-01-31
  • 2021-11-12
  • 2021-08-26
  • 2021-08-13
  • 2021-05-24
相关资源
相似解决方案