1. 程式人生 > >C#學習筆記第四篇之Equals,GetHashCode ,ToString函式深度剖析(二)

C#學習筆記第四篇之Equals,GetHashCode ,ToString函式深度剖析(二)



C#學習筆記第四篇之Equals,GetHashCode ,ToString函式深度剖析(二)

上一篇詳細搞了Equals,這一篇重點說下GetHashCode函式有什麼用,怎麼用,在哪裡用,用的時候注意什麼。

然後簡要說下ToString的意義所在,因為比較簡單,就不詳細說明了。

1、GetHashCode函式有什麼用?

依然參考官網的一句話來解釋,“A hash code is a numeric value that is used to insert and identify an object in a hash-based collection such as theclass”,大意就是說,HashCode就是來確定一個物件的唯一值,被用來當做那些運用了hash查詢的容器或者函式來進行插入或者唯一的確定查詢。

更通俗的講,就是,一個物件,當把這個物件新增到一個鍵值對這樣的容器(如Dictionary<Key,Value>)時,可以呼叫該物件的這個函式來得到一個唯一的HashCode(相當於一個物件的整數ID),把該值放入鍵值對容器中作為唯一的鍵值,可以進行查詢,插入操作。

再具體點講,就是,當我們放入兩個相同的物件如 string s1 = “aaa” ;string s2 = "aaa";,s1,s2放入Dictionary中時,我們知道Dictionary是不允許Key值相等的,那麼s1,s2,放入其中,他們的key時多少?如何得到這個key?對的,這個時候,GetHashCode函式就派上用場了,這個Dictionary就會呼叫這兩個物件的GetHashCode函式來得到兩個HashCode值,其實GetHashCode就是一個hash函式,把物件對映成唯一的一個物件ID,便於我們在把物件放入利用了hash對映的容器時,這些容器能得到每個物件的hash值,別的地方還真用不上呢。

2、這個函式是怎麼工作的?

因為每個類的父類都是Object類,所以定義的每個類中都預設有個繼承的方法GetHashCode,當然你完全可以重寫它。(有些時候還必須重寫,這正是本文重點說明的地方,因為預設的父類hashCode的值,是基於父類的引用值)

其實就是一hash函式,來產生一個值,然後返回,作為這個物件唯一的一個Id。

3、怎麼用?

通常只需要在物件中重寫就行了,但是要注意的是,該值一定要確保唯一,不要發生重複。如果重複的結果就是兩個不同的物件對應了同一個相同的Id(hashcode),這顯然不是我們想要的。

  public override int GetHashCode()
    { 
        return Tuple.Create(x, y).GetHashCode();
    } 

Tuple是一個序列化陣列,建立x,y,序列陣列,這是官網提供的一種hash對映方式,當然你可以發揮想象儘可能的確保x與y的計算組合值一定時,x與y也相同,因為我們要保證hashcode一樣,那麼兩個類也相同,同時也引出了下一條注意事項就是,重寫了hashcode這個函式,也一定要重寫Equals這個函式,並且確保hash值也是一樣的,不然相同的類對應不同的hashcode,多蛋疼啊。

If you override theGetHashCodemethod, you should also overrideEquals, and vice versa. If your overriddenEqualsmethod returnstruewhen two objects are tested for equality, your overriddenGetHashCodemethod must return the same value for the two objects.

If an object that is used as a key in a hash table does not provide a useful implementation of GetHashCode, you can specify a hash code provider by supplying an IEqualityComparer implementation to one of the overloads of the Hashtable class constructor。

官網的解釋是:要保證兩個相等的物件有唯一的一個hashcode值,(這當然是必須的啊!)保持語義的一致性。

所以一個完整的應該是:

public class DaichoKey : IEquatable<DaichoKey>
{
    public int ID { get; set; }
    public int SubID { get; set; }
 
    public bool Equals(DaichoKey other)
    {
        return this.ID == other.ID && this.SubID == other.SubID;
    }
    public override bool Equals(object obj)
    {
        if (obj == null) return base.Equals(obj);
 
        if (obj is DaichoKey)
            return Equals(obj as DaichoKey);
        else
            throw new InvalidCastException("the 'obj' Argument is not a DaichoKey object");
    }
    public override int GetHashCode()
    {
        return base.GetHashCode();//return object's hashcode
    }
}

另外要說的是,不僅僅是Dictionary這類容器,才需要重寫該函式,更重要的是,凡是要利用類的hashcode來作為key值來進行查詢的函式都要重寫,譬如說List,雖然是個線性表,但是它的函式Contains,IndexOf函式,都是利用類的hashcode值,來hash對映查詢的,所以如果要加入List的中類,沒有實現GetHashCode函式,它呼叫Contains和IndexOf函式時,相同的類物件,但它會找不到的。更為細節的討論,請看專題你要小心的GetHashCode這篇文章有詳細的解釋。

4、ToString作用?

就是不想幹巴巴的得到一個類的名字,當想把一個類的各個屬性值都取得並用於列印或者其他用途是,返回一個類的字串比返回一個類的引用值要有用的多。