| 2. 比較子的重載 C#中有6個比較子,它們分為3對: ● == 和 != ● > 和 < ● >= 和 <= C#要求成對重載比較子。如果重載了==,也必須重載!=,否則會產生編譯錯誤。另外,比較子必須返回bool類型的值。這是它們與算術運算子的根本區別。兩個數相加或相減的結果,理論上取決於數的類型。而兩個Vector的相乘會得到一個標量。另一個例子是.NET基類System.DateTime,兩個DateTime執行個體相減,得到的結果不是DateTime,而是一個System.TimeSpan執行個體,但比較運算得到的如果不是bool類型的值,就沒有任何意義。 注意: 在重載==和!=時,還應重載從System.Object中繼承的Equals()和GetHashCode()方法,否則會產生一個編譯警告。原因是Equals()方法應執行與==運算子相同的相等邏輯。 除了這些區別外,重載比較子所遵循的規則與算術運算子相同。但比較兩個數並不像想象的那麼簡單,例如,如果比較兩個對象引用,就是比較儲存物件的記憶體位址。比較子很少進行這樣的比較,所以必須編寫運算子,比較對象的值,返回相應的布爾結果。下面給Vector結構重載==和!=運算子。首先是==的執行代碼: public static bool operator = = (Vector lhs, Vector rhs) { if (lhs.x = = rhs.x && lhs.y = = rhs.y && lhs.z = = rhs.z) return true; else return false; } 這種方式僅根據向量組成部分的值,來對它們進行等於比較。對於大多數結構,這就是我們希望的,但在某些情況下,可能需要仔細考慮等於的含義,例如,如果有嵌入的類,是應比較對同一個對象的引用(淺度比較),還是應比較對象的值是否相等(深度比較)? 注意: 不要通過調用從System.Object中繼承的Equals()方法的執行個體版本,來重載比較子,如果這麼做,在objA是null時計算(objA==objB),這會產生一個異常,因為.NET運行庫會試圖計算null.Equals(objB)。採用其他方法(重寫Equals()方法,調用比較子)比較安全。 還需要重載運算子!=,採用的方式如下: public static bool operator != (Vector lhs, Vector rhs) { return ! (lhs == rhs); } 像往常一樣,用一些測試代碼檢查重寫方法的工作情況,這次定義3個Vector對象,並進行比較: static void Main() { Vector vect1, vect2, vect3; vect1 = new Vector(3.0, 3.0,–10.0); vect2 = new Vector(3.0, 3.0,–10.0); vect3 = new Vector(2.0, 3.0, 6.0); Console.WriteLine("vect1= =vect2 returns " + (vect1= =vect2)); Console.WriteLine("vect1= =vect3 returns " + (vect1= =vect3)); Console.WriteLine("vect2= =vect3 returns " + (vect2= =vect3)); Console.WriteLine(); Console.WriteLine("vect1!=vect2 returns " + (vect1!=vect2)); Console.WriteLine("vect1!=vect3 returns " + (vect1!=vect3)); Console.WriteLine("vect2!=vect3 returns " + (vect2!=vect3)); } 編譯這些代碼(下載代碼中的Vectors3.cs),會得到一個編譯器警告,因為我們沒有為Vector重寫Equals(),對於本例,這是不重要的,所以忽略它。 csc Vectors3.cs Microsoft (R) Visual C# 2005 Compiler version 8.00.50215.33 for Microsoft (R) Windows (R) Framework version 2.0.50215 Copyright (C) Microsoft Corporation 2001-2005. All rights reserved. Vectors3.cs(5,11): warning CS0660: 'Wrox.ProCSharp.OOCSharp.Vector' defines operator = = or operator != but does not override Object.Equals(object o) Vectors3.cs(5,11): warning CS0661: 'Wrox.ProCSharp.OOCSharp.Vector' defines operator = = or operator != but does not override Object.GetHashCode() 在命令列上運行該樣本,產生如下結果: Vectors3 vect1= =vect2 returns True vect1= =vect3 returns False vect2= =vect3 returns False vect1!=vect2 returns False vect1!=vect3 returns True vect2!=vect3 returns True 3. 可以重載的運算子並不是所有的運算子都可以重載。可以重載的運算子如表5-5所示。 表 5-5
類 別 |
運 算 符 |
限 制 |
算術二元運算子 |
+, *, /, –, % |
無 |
算術一元運算子 |
+, –, ++, –– |
無 |
按位二元運算子 |
&, |, ^, <<, >> |
無 |
按位一元運算子 |
!, ~, true, false |
true和false運算子必須成對重載 |
比較子 |
==, !=, >=, <, <=, > |
必須成對重載 |
賦值運算子 |
+=,–=,*=,/=,>>=,<<=,%= ,&=,|=,^= |
不能顯式重載這些運算子,在重寫單個運算子如+,–,%等時,它們會被隱式重寫 |
索引運算子 |
[] |
不能直接重載索引運算子。第2章介紹的索引器成員類型允許在類和結構上支援索引運算子 |
資料類型轉換運算子 |
() |
不能直接重載資料類型轉換運算子。使用者定義的資料類型轉換(本章的後面介紹)允許定義定製的資料類型轉換 |
|