C#的相等判断

什么是相等

在C#中我们经常会需要判断两个变量是否相等,相等理论上有两种:

  • 同一性(identity),即是否两个变量是否指向同一个对象。
  • 相等性(equality),即两个变量内部的值是否相同,例如两个字符串的内容是否相同。

显然如果两个变量是相同对象,那么它们也必然相等。根据具体使用的上下文我们可能需要判断同一性或者相等性之一,因此就需要了解如何进行判断。

C#判断相等的方式

C#的System.Object类提供了如下方式来判断对象的相等性:

public static bool Equals(Object? objA, Object? objB);
public static bool ReferenceEquals(Object? objA, Object? objB);
public virtual bool Equals(Object? obj);
operator ==;

首先是ReferenceEquals,这个顾名思义就是判断两个变量是否引用同一个对象,在需要明确判断引用相等的时候可以使用这个函数。

其次是Equals方法,这个方法在Object类中定义,默认实现是调用ReferenceEquals,即判断引用是否相等。但是我们看到这是一个虚方法,因此很多类型重写了这个方法,例如String类型,重写后比较的是字符串的内容是否相同。

而相等运算符和Equals方法类似,也可以被重载,以实现自定义类型的相等判断。根据官方文档介绍,对于值类型是判断其内部值是否相同,对于引用类型是默认判断是否引用同一对象,对于委托和字符串等也有各自的实现。

值得注意的是,用户定义的struct类型默认没有支持==操作符,但是可以使用ValueType的Equals方法来判断两个值类型的内部值是否相同,例如:

static void Main(string[] args)
{
    Point p1 = new Point(1, 1);
    Point p2 = new Point(1, 1);
    Console.WriteLine("p1 == p2:{0}", p1.Equals(p2)); // 输出 p1 == p2:True
    Console.WriteLine("p1 == p2:{0}", p1 == p2); // 编译错误 Operator '==' cannot be applied to operands of type 'Point' and 'Point'
}

internal struct Point
{
    private Int32 m_x, m_y;
    public Point(Int32 x, Int32 y)
    {
        m_x = x;
        m_y = y;
    }
}

综上,C#提供了多种方式来判断对象的相等性,包括引用相等和值相等,开发者需要根据具体需求选择合适的方法进行判断。

如何自定义相等判断

我们自定义的类如果需要实现自己的相等判断逻辑,那么可以重载Object的public virtual bool Equals(Object? obj)方法以及重写==操作运算符,如果重写了其中之一,那么推荐也重写另一个相等判断,否则可能由于使用习惯使用了没有重写的相等判断造成bug。

重写时需要注意相等性判断要符合一下特性:

  • 自反性。x.Equals(x) 应该返回 true
  • 对称性。x.Equals(y) 应该返回和 y.Equals(x) 相同的结果
  • 可传递。x.Equals(y) 和 y.Equals(z) 都返回 true,那么 x.Equals(z) 也应该返回 true
  • 一致性。x.Equals(y) 多次调用应该返回相同的结果,除非x或y的值发生了变化。

如果重写了public virtual bool Equals(Object? obj)方法,那么也应该重写GetHashCode方法,因为相等的对象必须有相同的哈希码,否则以这个类的对象作为key来索引时会导致相同的对象索引到不同的数据,而且编译器也会给出有一个编译警告

除了使用继承来的Object的相关方法来判断相等,我们还可以继承IEquatable接口实现自己的Equals方法,该方法和Object的Equals方法类似,但是类型更安全,因为它的参数是该类型的变量,而不是Object对象,不需要装箱和拆箱操作。

posted @ 2024-09-02 21:11  heanrum  阅读(172)  评论(0)    收藏  举报