申明
原文为《Effective C#》中内容,作者为 Addison Wesley
仅做翻译和修改(原文太长太罗嗦),但并不修改作者的原意。
C# 中的相等关系
当你定义了一个自己的类型后,你需要明确一下“相等”关系对你的类型来说意味着什么。
你可以使用 C# 提供的四种方法来判断他们是否相等。
public static bool ReferenceEquals(object left, object right);
public static bool Equals(object left, object right);
public virtual bool Equals(object right);
public static bool operator ==(MyClass left, MyClass right);
前两个是 Object 的静态方法,第三个是实例的方法,最后一个是 == 操作符。
变成语言允许你自定义这四个方法,但是并不提倡。前两个一定不要碰;实例的 Equals() 方法需要经常重写;== 操作符偶尔需要重写,特别是当考虑到值类型性能的时候。
除此以外,在这四个方法之间也有一定的联系,当你修改其中一个的时候也会影响到另外的几个。
这四个方法也不是比较相等的唯一方法,引用类型重写 Equals() 的时候必须实现 IEquatable
(这个 IStructuralEquality 网上都搜索不到任何信息,知识在 MSDN 的一篇文章中提到了一下,在代码中也找不到,难道是被扼杀在萌芽之中了?)
C#中,判断引用类型是否相等是看他们是不是被引用到了同一个对象上;而判断值类型是否相等,就看他们的结构和值是否相等。
这就是为什么“相等”测试需要那么多不同的方法。
Object 类型中的两个静态方法
首先要明确一下,这两个方法你比应该去重新定义它
Object.ReferenceEquals() 这个方法返回两个引用类型是否被引用到了同一个对象上,也就是说他们拥有相同的身份;
所以这个方法比较的是相同的“身份”,而不是相同的“值”,也就是说让你对两个值类型进行比较的时候,结果永远是 false;
int i = 5;
int j = 5;
if (Object.ReferenceEquals(i, j))
Console.WriteLine("Never happens.");
else
Console.WriteLine("Always happens.");
if (Object.ReferenceEquals(i, i))
Console.WriteLine("Never happens.");
else
Console.WriteLine("Always happens.");
Object.Equals() 这个方法你也不应该去重新定义它,这个方法是当你不确定两个变量在运行中的类型时采用的,Object 是所有类型的基类,所以这个方法可以传入任何类型;
这个方法是这样实现的:
public static new bool Equals(object left, object right)
{
// Check object identity
if (Object.ReferenceEquals(left, right) )
return true;
// both null references handled above
if (Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null))
return false;
return left.Equals(right);
}
现在理解为什么不应该重新定义这两个方法了吗?因为第一个你不能去重新定义它,而第二个你没必要去重新定义它,因为它最后调用的是类型本身的 Equals() 方法。
本作品由 Dozer 创作,采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。