《C#高效编程》读书笔记06-理解几个等同性判断之间的关系
当创建自定义类型时(无论是class还是struct),应为类型定义"等同性"的含义。C#提供了4种不同的函数来判断两个对象是否"相等":
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.ReferenceEquals()
和Object.Equals()
这两个系统提供的静态方法,永远都不需要重新定义。
Object.ReferenceEquals()
判断的是对象引用,判断的是否拥有同样的对象标识(object identity),所以若将一个值类型与它自身进行比较,方法返回的是false
,因为值类型会进行装箱操作,造成引用地址不同。
Object.Equals()
对于引用类型默认使用对象标识判断,即跟Object.ReferenceEquals()
一样,但对于值类型,因为System.ValueType重写了Object.Equals()
方法,所以比较的是值是否相等(主要是struct),但System.ValueType是所有值类型的基类,故实现比较时,用的是反射,效率并不高。
综上所述,自定义类型实现自己的比较方法就比较重要了。
public class Student : IEquatable<Student>
{
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
if (Object.ReferenceEquals(obj, null))
return false;
if (Object.ReferenceEquals(this, obj))
return true;
if (this.GetType() != obj.GetType())
return false;
return this.Equals(obj as Student);
}
public bool Equals(Student other)
{
if (this.Id != other.Id)
return false;
if (this.Name != other.Name)
return false;
return true;
}
}
注意,重写Equals
方法时,需要同时重写GetHashCode()
方法,详细可查看条目7。
operator==()
则相对简单。只要创建的是值类型,都必须重定义operator==()
。理由和重写System.ValueType的Equals
是一样的。而引用类型则应该避免重写operator==()
。