Fork me on Gitee

AIGC标识 C# 中 Equals 与 == 的区别

在 C# 中,Equals== 都可以用来“比较”,但它们比较的逻辑并不完全相同。最核心的一句话是:

== 是运算符,可以被重载;Equals() 是方法,通常用于判断对象的“相等性”。

可以从几个层面理解。

1. 基本类型:看起来基本一样

int a = 10;
int b = 10;

Console.WriteLine(a == b);      // True
Console.WriteLine(a.Equals(b)); // True

对于 intdoublebool 等值类型,通常都是比较值。

例如:

double a = 3.14;
double b = 3.14;

a == b;        // True
a.Equals(b);   // True

2. 引用类型:== 默认比较引用,Equals() 可以比较内容

这是最重要的区别。

class Person
{
    public string Name { get; set; }
}

Person p1 = new Person { Name = "张三" };
Person p2 = new Person { Name = "张三" };

Console.WriteLine(p1 == p2);
Console.WriteLine(p1.Equals(p2));

如果 Person 没有重写任何方法:

p1 == p2       → False
p1.Equals(p2)  → False

原因是:

p1 ──→ 对象A { Name = "张三" }

p2 ──→ 对象B { Name = "张三" }

虽然两个对象的内容一样,但它们是两个不同的对象。

默认情况下:

p1 == p2

比较的是两个引用是否指向同一个对象。

而:

p1.Equals(p2)

如果 Person 没有重写 Equals(),最终也是按照引用来判断。


3. string 是一个非常典型的例外

string s1 = "hello";
string s2 = "hello";

Console.WriteLine(s1 == s2);      // True
Console.WriteLine(s1.Equals(s2)); // True

很多初学者会认为:

“引用类型使用 == 比较地址。”

这句话并不完全正确。

因为 == 可以被重载。

string 就重载了 ==,所以:

s1 == s2

比较的是字符串内容。

也就是说:

string a = "ABC";
string b = "ABC";

a == b

实际上可以理解为:

比较字符串内容是否相同

而不是简单比较两个引用。


4. 自定义类可以重写 Equals

例如:

class Person
{
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        Person other = obj as Person;

        if (other == null)
            return false;

        return Name == other.Name;
    }

    public override int GetHashCode()
    {
        return Name?.GetHashCode() ?? 0;
    }
}

现在:

Person p1 = new Person { Name = "张三" };
Person p2 = new Person { Name = "张三" };

Console.WriteLine(p1 == p2);
Console.WriteLine(p1.Equals(p2));

结果仍然可能是:

False
True

因为你只重写了 Equals(),没有重载 ==

这说明:

==       → 看 == 运算符的实现
Equals   → 看 Equals() 的实现

两者是相互独立的。


5. 如果同时重载 ==Equals

可以这样:

class Person
{
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        Person other = obj as Person;

        return other != null && Name == other.Name;
    }

    public override int GetHashCode()
    {
        return Name?.GetHashCode() ?? 0;
    }

    public static bool operator ==(Person a, Person b)
    {
        if (ReferenceEquals(a, b))
            return true;

        if (a is null || b is null)
            return false;

        return a.Name == b.Name;
    }

    public static bool operator !=(Person a, Person b)
    {
        return !(a == b);
    }
}

那么:

Person p1 = new Person { Name = "张三" };
Person p2 = new Person { Name = "张三" };

Console.WriteLine(p1 == p2);      // True
Console.WriteLine(p1.Equals(p2)); // True

这时候两种比较的语义就统一了。


6. ReferenceEquals() 又是什么?

C# 中还有一个非常重要的方法:

object.ReferenceEquals(a, b)

它的含义非常明确:

判断两个变量是否指向同一个对象。

例如:

Person p1 = new Person();
Person p2 = new Person();

Person p3 = p1;

Console.WriteLine(p1 == p2);                    // False
Console.WriteLine(object.ReferenceEquals(p1,p2)); // False

Console.WriteLine(p1 == p3);                    // True
Console.WriteLine(object.ReferenceEquals(p1,p3)); // True

可以把三个概念简单理解成:

== 
↓
运算符比较
可以被重载
具体比较什么取决于类型

Equals()
↓
相等性比较
可以被重写
通常用于判断两个对象“逻辑上是否相等”

ReferenceEquals()
↓
引用比较
判断是不是同一个对象

7. 一个非常重要的实际例子

假设:

class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

现在:

User u1 = new User
{
    Id = 1,
    Name = "张三"
};

User u2 = new User
{
    Id = 1,
    Name = "张三"
};

虽然:

u1.Id == u2.Id
u1.Name == u2.Name

但是:

u1 == u2

默认仍然是:

False

因为:

u1 → 对象A

u2 → 对象B

如果你的业务定义是:

Id 相同就认为是同一个用户

那么就应该重写 Equals(),甚至同时重载 ==


8. 实际开发中怎么选择?

可以记这个表:

场景 推荐
intdoublebool 等值类型比较 ==
字符串比较 ==Equals()
判断两个对象逻辑上是否相等 Equals()
判断是不是同一个对象 ReferenceEquals()
自定义类型需要 == 表示业务相等 重载 ==
Dictionary / HashSet 判断对象相等 Equals() + GetHashCode()

尤其需要注意:

Equals()

如果你重写了,就应该同时考虑:

GetHashCode()

因为:

Dictionary<TKey, TValue>
HashSet<T>

等集合会依赖对象的相等性和哈希值。


9. 最容易记错的地方

不要简单记成:

==       = 比较地址
Equals   = 比较内容

这是不准确的。

正确理解应该是:

== 
→ 运算符
→ 可以重载
→ 不同类型的行为可能不同

Equals()
→ 方法
→ 可以重写
→ 用来定义“两个对象是否相等”

ReferenceEquals()
→ 专门判断两个引用是否指向同一个对象

例如:

string a = new string(new[] { 'a', 'b', 'c' });
string b = new string(new[] { 'a', 'b', 'c' });

Console.WriteLine(a == b);                         // True
Console.WriteLine(a.Equals(b));                    // True
Console.WriteLine(object.ReferenceEquals(a, b));   // False

这个例子非常适合理解三者的区别:

a 和 b

内容相同       → ==          True
逻辑相等       → Equals      True
是不是同一个对象 → ReferenceEquals False
posted @ 2026-08-17 12:57  ThesunKomorebi  阅读(5)  评论(0)    收藏  举报