Tip12 重寫Equals時也要重寫GetHashCode

Tip12 重寫Equals時也要重寫GetHashCode
如果重寫Equals方法但不重寫GetHashCode方法,在使用如FCL中的Dictionary類時,可能隱含一些潛在的Bug。例如:

        class Person
        {
            public string IDCode { get; private set; }

            public Person(string idCode)
            {
                this.IDCode = idCode;
            }

            public override bool Equals(object obj)
            {
                return IDCode == (obj as Person).IDCode;
            }
        }

        class PersonMoreInfo
        {
            public string SomeInfo { get; set; }
        }

        static void Main(string[] args)
        {
            AddAPerson();
            Person mike = new Person("NB123");

            //Console.WriteLine(mike.GetHashCode());
            //得到的HashCode與AddAPerson中的HashCode不一樣

            Console.WriteLine(PersonValues.ContainsKey(mike));
        }

        static void AddAPerson()
        {
            Person mike = new Person("NB123");
            PersonMoreInfo mikeValue = new PersonMoreInfo() { SomeInfo = "Mike's info" };
            PersonValues.Add(mike, mikeValue);
            //Console.WriteLine(mike.GetHashCode());
            Console.WriteLine(PersonValues.ContainsKey(mike));
        }

輸出的結果是

True
False

理論上來說,AddAPerson中的mike和Main方法中的mike屬於“值相等”,將該“值”作爲key放入Dictionary中,再在某處根據mike將mikeValue取出來,這是理所當然的。針對同一個示例,這種結論是正確的,但針對不同的mike示例額,這種結果就有問題了。
原因是基於鍵值的集合(如Dictionary)是根據Key值的HashCode(調用類型的GetHashCode方法)來查找Value值。

注:GetHashCode方法應該基於只讀的屬性或特性生成HashCode。

GetHashCode方法存在一個問題:永遠只返回一個整型類型,而整型類型的容量無法滿足字符串的容量,例如:

string str1 = "NB0903100006";
string str2 = "NB0904140001";
//輸出結果是一樣的
Console.WriteLine(str1.GetHashCOde());
Console.WriteLine(str2.GetHashCOde());

Person類型對GetHashCode方法稍作改進後可以減少產生相同HashCode的機率。
Person類型的最終版本應該如下:

    class Person : IEquatable<Person>
    {
        public string IDCode { get; private set; }

        public Person(string idCode)
        {
            this.IDCode = idCode;
        }

        public override bool Equals(object obj)
        {
            return IDCode == (obj as Person).IDCode;
        }

        public override int GetHashCode()
        {
            return (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + this.IDCode).GetHashCode();
        }

        public bool Equals(Person other)
        {
            return IDCode == other.IDCode;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章