C# 所有類別直接或間接繼承自 System.Object,實現單根繼承。未明確指定繼承類別時,編譯器預設繼承 System.Object。object 關鍵字與 System.Object 完全等同。所有類別繼承 Object 公共介面,剖析它們對理解 C# 類別行為至關重要。
namespace System
{
public class Object
{
public static bool Equals(object objA, object objB) { }
public static bool ReferenceEquals(object objA, object objB) { }
public Object() { }
public virtual bool Equals(object obj) { }
public virtual int GetHashCode() { }
public Type GetType() { }
public virtual string ToString() { }
protected virtual void Finalize() { }
protected object MemberwiseClone() { }
}
}
先釐清面向物件兩個重要相等概念:
值型別用 == 判斷值相等(結構/列舉未定義 == 需自行定義)。參考型別用 == 判斷參考相等。值型別通常無參考相等表示,非受控程式設計才用 & 間接判斷位址。
先檢查兩物件是否皆為 null,是則回傳 true,否則呼叫 objA.Equals(objB) 並回傳結果。歸結於實例方法 Equals(object obj)。
預設實現為 { return this == obj; } 即判斷參考相等。但為 virtual 方法,C# 建議重寫以判斷值相等。.NET 框架許多型別重寫此法(String、Int32 等),但部分未重寫(Array 等),使用時需注意。參考型別未重寫時,調用相當於參考相等判斷。所有值型別(隱含繼承 ValueType)皆重寫 Equals 判斷值相等。
注意:x.Equals(null) 回傳 false(x 不能為 null,否則拋出空參考異常)。這也是設計靜態 Equals(objA, objB) 的原因——當兩物件皆可能為 null 時,只能用靜態方法判斷值相等。
Equals 應與 == 回傳值一致。重寫 Equals 應同時重載/定義 ==,反之亦然。雖 ValueType 已重寫,但 C# 建議重寫自訂值型別 Equals(系統實作較低效)。Equals 表達值相等,一般不應重載 ==(預設語義為參考相等)。判斷兩物件是否參考相等。參考型別時語義同未重載 ==。值型別時必回傳 false。