C# Equals 与 ==

目录

1. Equals 与 ==本质区别

2.Equals 与 == 详细对比

3. Equals 与 ==示例说明

(1)值类型(如 int、struct)

(2)引用类型(如 string、class)

(3)自定义相等逻辑

   as 运算符与强制转换的对比

4. 注意事项

总结


在 C# 中,Equals 和 == 都用于比较两个对象是否相等,但它们的行为和使用场景有显著区别,主要体现在比较方式、适用类型和自定义逻辑等方面。

1. 本质区别

  • Equals:是 object 类定义的虚方法,用于比较两个对象的值是否相等(默认行为),可被重写以实现自定义相等逻辑。Equals 判断是否相等 和Tostring 一样都是位于Object基类中的虚方法  .NET 类的最终基类  所以所有的类中基本都有 Equals 和Tostring 等方法
  • ==:是运算符,默认情况下,对于值类型比较值是否相等,对于引用类型比较引用(内存地址)是否相同,也可被重载以改变行为。

2. 详细对比

特性Equals 方法== 运算符
定义虚方法(public virtual bool Equals(object obj)静态运算符(public static bool operator ==(T a, T b)
默认行为(值类型)比较值是否相等(通过 ValueType 重写实现)比较值是否相等
默认行为(引用类型)比较引用是否相同(与 == 一致)比较引用是否相同(内存地址是否一致)
可定制性可重写(override)以实现值比较逻辑可重载(operator ==)以自定义比较逻辑
空值处理调用 null.Equals(...) 会抛空引用异常可在重载时处理 null,避免异常
适用场景多用于对象实例间的值比较,尤其是自定义类型多用于简单值比较或希望保持引用比较的场景

3. 示例说明

(1)值类型(如 intstruct

对于值类型,Equals 和 == 默认行为一致,均比较值是否相等:

int a = 5;
int b = 5;

Console.WriteLine(a.Equals(b));  // True(比较值)
Console.WriteLine(a == b);       // True(比较值)
(2)引用类型(如 stringclass
  • string 特殊处理string 是引用类型,但 C# 对其 == 进行了重载,使其行为与 Equals 一致(比较字符串内容):

    string s1 = "hello";
    string s2 = "hello";
    string s3 = new string("hello".ToCharArray());  // 新实例,引用不同 将字符串转换为字符数组(char[])
    
    Console.WriteLine(s1.Equals(s2));  // True(内容相同)
    Console.WriteLine(s1 == s2);       // True(重载后比较内容)
    Console.WriteLine(s1 == s3);       // True(内容相同)
    
  • 自定义类(默认行为):未重写 Equals 和未重载 == 时,两者都比较引用:

    public class Person {
        public string Name { get; set; }
        public Person(string name) => Name = name;
    }
    
    Person p1 = new Person("Alice");
    Person p2 = new Person("Alice");
    Person p3 = p1;
    
    Console.WriteLine(p1.Equals(p2));  // False(引用内容地址不同)
    Console.WriteLine(p1 == p2);       // False(引用不同)
    Console.WriteLine(p1 == p3);       // True(引用相同)
    
(3)自定义相等逻辑

通过重写 Equals 和重载 ==,可实现基于属性的比较:

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

    public Person(string name, int age) {
        Name = name;
        Age = age;
    }

    // 重写 Equals 比较属性
    public override bool Equals(object obj)
    {
        Person c = obj as Person;
        //在这this就指向调用此方法的数据(对象)
        if (this.Age == c.Age && this.Name == c.Name)
        {
            return true;
        }
        return false;
    }

    // 重载 == 运算符
    public static bool operator ==(Person a, Person b) {
        if (a is null && b is null) return true;
        if (a is null || b is null) return false;
        return a.Name == b.Name && a.Age == b.Age;
    }

    // 必须同时重载 !=
    public static bool operator !=(Person a, Person b) => !(a == b);

    // 建议同时重写 GetHashCode(用于哈希表等场景)
    public override int GetHashCode() => HashCode.Combine(Name, Age);
}

// 使用
Person p1 = new Person("Alice", 30);
Person p2 = new Person("Alice", 30);
Console.WriteLine(p1.Equals(p2));  // True(属性相同)
Console.WriteLine(p1 == p2);       // True(属性相同)

注:在 C# 中,Class1 c = obj as Class1; 是一种安全的类型转换方式,用于将对象 obj 转换为 Class1 类型。它的行为与强制类型转换((Class1)obj)类似,但有一个重要区别:

如果转换失败(即 obj 不是 Class1 类型且不能被隐式转换为 Class1),as 运算符会返回 null,而不会抛出 InvalidCastException 异常。

与强制转换的对比

转换方式成功时行为失败时行为适用类型
as 运算符返回转换后的对象返回 null引用类型、可空值类型
强制转换 (T)返回转换后的对象抛出 InvalidCastException所有类型(值类型、引用类型)

4. 注意事项

  • null 安全:调用 obj.Equals(...) 前需确保 obj 不为 null,否则会抛异常;而 == 可在重载时处理 null(如 a == b 即使 a 为 null 也不会异常)。
  • GetHashCode 配合:重写 Equals 时必须重写 GetHashCode,否则可能导致哈希表(如 Dictionary)行为异常。
  • 一致性:建议保持 Equals 和 == 的行为一致(要么都比较值,要么都比较引用),避免混淆。
  • 结构体:对于自定义 structEquals 默认比较所有字段,而 == 需显式重载才能使用(否则编译错误)。

总结

  • 对于值类型,两者默认行为一致(比较值)。
  • 对于引用类型,默认均比较引用,但若类型重载了 ==(如 string)或重写了 Equals,则可能比较值。
  • 自定义类型时,根据需求重写 Equals 和重载 ==,以实现符合业务逻辑的相等比较。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值