DAY 15 類別(四)
類別
如果把繼承也算上去的話,今天就是第六天的類別介紹了,在把類別講得更完整吧!
優化類別
還記得在 DAY 10 隨口提到的類別的基底類別是 object,所以我們自己做的類別,實作後也都有 object 的方法,但由於我們沒有在再定義內容,所以有些方法可能不能用,或者不如預期,所以今天來把這些方法弄完整。
那我們來做一個座標類別來示範
1 2 3 4 5 6 7 8
| class Coordinate { public Coordinate (decimal longitude, decimal latitude) { this.longitude = longitude; this.latitude = latitude; } public decimal longitude { get; } public decimal latitude { get; } }
|
ToString
1 2 3
| Coordinate c1 = new Coordinate (12.156m, 7.195m); Console.WriteLine (c1); Console.ReadKey ();
|
可以看到顯示的是demo.Program+Coordinate
,因為我的命名空間是 demo,所以每個人看到的可能不一樣,但這資訊都是對我們沒有幫助的,我們希望 ToString 得內容應該要能正確地獲得類別相關資訊,所以我們要
1 2 3
| public override string ToString () { return $"longitude: {longitude}, latitude: {latitude}"; }
|
因為 Console.WriteLine() 方法會呼叫對象的 ToString() 方法,而 object.ToString() 預設輸出類別名稱,就會發生印出不需要的內容,所以把 ToString 改成是轉出我們的相關成員的字串,之後印出這個類別就能得到有用的資訊。
GetHashCode
因為做比較時 Equals() 會警告你需先重寫 GetHashCode(),不寫不會讓程式編譯失敗,但寫好程式的幾個要點之一就是,程式執行後不要有任何的警告。
1 2 3 4 5 6 7
| public override int GetHashCode () { int hashCode = longitude.GetHashCode (); if (longitude.GetHashCode () != latitude.GetHashCode ()) { hashCode ^= latitude.GetHashCode (); } return hashCode; }
|
簡單來說,只要經緯度一樣,我們就得到的 HashCode 就會是一樣,至於為什麼要用 xor(^) 來操作,因為如果是以相加減來說,較容易出現不同經緯而數值一樣的狀況,但使用 and 容易變成全是 0,or 容易全是 1,所以通常都是用 xor 來做 HashCode 的處理。
Equals
有了 GetHashCode 後,我們就可以來比較類別了。
假設我們希望兩個物件只要內容一樣就表示相等,即便參考位置不一樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Coordinate c1 = new Coordinate (12.156m, 7.195m); Coordinate c2 = c1; Coordinate c3 = new Coordinate (12.156m, 7.195m); if (Coordinate.ReferenceEquals (c1, c2)) { Console.WriteLine ("c1 與 c2 參考位置相等"); } if (c1.Equals (c2)) { Console.WriteLine ("c1 與 c2 相等"); } if (Coordinate.ReferenceEquals (c1, c3)) { Console.WriteLine ("c1 與 c3 參考位置相等"); } if (c1.Equals (c3)) { Console.WriteLine ("c1 與 c3 相等"); } Console.ReadKey ();
|
可以看到 c1 一個也不跟 c3 相等,但我們希望 Equals() 時,顯示是 true,所以我們來改寫吧
1 2 3 4 5 6 7
| public override bool Equals (object obj) { if (obj == null) return false; if (this.GetType () != obj.GetType ()) return false; return this.GetHashCode () == obj.GetHashCode (); }
|
首先檢查 obj 是不是 null,再檢查型別一不一樣,然後就是用我們上面做過的方法,來確認值一不一樣。
但很多人可能使用 ==
來比較多過於使用 Equals(),但你會發現 (c1 == c3) == false
,所以我們要來重寫運算子。
比較運算子
我們就把==
做成跟我們 Equals() 一樣,不管參考位置
1 2 3 4 5 6
| public static bool operator == (Coordinate c1, Coordinate c2) { return c1.Equals (c2); } public static bool operator != (Coordinate c1, Coordinate c2) { return !c1.Equals (c2); }
|
因為重寫 ==
需要連同 !=
一起重寫,這樣我們就可以使用 ==
來做比較了。
加法類運算子
再來就是加減的時候,能夠把經緯度相加減。
1 2 3 4 5 6
| public static Coordinate operator + (Coordinate c1, Coordinate c2) { return new Coordinate (c1.longitude + c2.longitude, c1.latitude + c2.latitude); } public static Coordinate operator - (Coordinate c1, Coordinate c2) { return new Coordinate (c1.longitude - c2.longitude, c1.latitude - c2.latitude); }
|
相加減後會傳回一個新的座標類別
1 2 3 4
| Coordinate c1 = new Coordinate (12.156m, 7.195m); Coordinate c2 = new Coordinate (12.06m, 1.516m); Console.WriteLine (c1 + c2); Console.ReadKey ();
|
一些小結論
今天只重寫了我覺得比較常用到的部分,還有很多很多的運算子可以重寫,就請大家自己練習了,最後附上這次完整的範例類別程式碼。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Coordinate { public Coordinate (decimal longitude, decimal latitude) { this.longitude = longitude; this.latitude = latitude; } public decimal longitude { get; } public decimal latitude { get; } public override string ToString () { return $"longitude: {longitude}, latitude: {latitude}"; } public override int GetHashCode () { int hashCode = longitude.GetHashCode (); if (longitude.GetHashCode () != latitude.GetHashCode ()) { hashCode ^= latitude.GetHashCode (); } return hashCode; } public override bool Equals (object obj) { if (obj == null) return false; if (this.GetType () != obj.GetType ()) return false; return this.GetHashCode () == obj.GetHashCode (); } public static bool operator == (Coordinate c1, Coordinate c2) { return c1.Equals (c2); } public static bool operator != (Coordinate c1, Coordinate c2) { return !c1.Equals (c2); } public static Coordinate operator + (Coordinate c1, Coordinate c2) { return new Coordinate (c1.longitude + c2.longitude, c1.latitude + c2.latitude); } public static Coordinate operator - (Coordinate c1, Coordinate c2) { return new Coordinate (c1.longitude - c2.longitude, c1.latitude - c2.latitude); } }
|
感謝閱讀。