C# 相等性判斷有四個方法:
1 public static bool ReferenceEquals(object left, object right);
2 public static bool Equals(object left, object right);
3 public virtual bool Equals(object right);
4 public static bool operator ==(MyClass left, MyClass right);
ReferenceEquals方法:使用場景是比較兩個變量是否為同一個引用。對於引用類型,比較兩個變量是否為同一個引用。對於值類型,先裝箱,再比較裝箱后的變量是否為同一個引用。顯然,對於值類型,ReferenceEquals方法的結果必定是False。
ReferenceEquals方法,用戶不應該重寫。為什么?重寫的原因是:原有的實現不能完成用戶所期望的功能。ReferenceEquals方法就是比較變量是否指向同一個引用,用戶不應該期望ReferenceEquals方法完成其他的功能。
靜態Equals方法:使用場景是不清楚兩個變量運行時的類型,因為變量可能是值類型、引用類型或者為Null。內部調用 left變量的實例Equals方法。靜態Equals方法,用戶不應該重寫。
實例Equals方法:使用場景是比較兩個變量的內容是否相等。引用類型的父類是Object(當然值類型的父類也是Object,但是值類型的直接父類是ValueType),Object的實例Equals方法比較的是是否為同一個引用,因此引用類型應該重寫實例Equals方法,使實例Equals方法成為內容的比較。對於值類型,值類型的直接父類ValueType已經重寫了Object的實例Equals方法,使實例Equals方法成為內容的比較,因此理論上說,所有的值類型都不需要再重寫實例Equals方法了。但是。仔細想想,ValueType是如何做到使實例Equals方法成為內容比較的?顯然,ValueType不知道自己有哪些子類,也不知道子類有哪些成員,這就意味着,使用反射技術來實現。反射的效率很低,因此,對於值類型,有必要重寫實例Equals方法。
==運算符:運算符比方法使用起來方便。對於值類型,==應該是比較內容;對於引用類型,==應該是比較是否為同一個引用。因此,值類型應該重載==,引用類型不應該重載==。
|
值類型 |
引用類型 |
說明 |
ReferenceEquals方法 |
是否為同一個引用 |
是否為同一個引用 |
都不應該重寫 |
靜態Equals方法 |
內容是否相等 |
內容是否相等 |
都不應該重寫(不知道變量運行時的類型) |
實例Equals方法 |
內容是否相等 |
內容是否相等 |
都應該重寫 |
==運算符 |
內容是否相等 |
是否為同一個引用 |
值類型應該重寫,引用類型不應該重寫 |
表格列出的是一般情況下應該遵守的規則,但是有些情況並不是如此。比如string,string是個特殊的引用類型,很多地方類似值類型。string的實例Equals方法和==運算符都是比較內容。