You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在包含子集合的类中正确重写Equals方法

如何正确实现包含集合属性的类的相等性检查

你定义了Person类和Address类,重写了它们的Equals和GetHashCode方法,但比较两个属性完全相同的Person实例时,相等性检查返回false。

你的原始代码如下:

原始类定义

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

    public List<Address> Addresses { get; set; }

    public override bool Equals(object? obj)
    {
        return obj is Person person &&
               Name == person.Name &&
               EqualityComparer<List<Address>>.Default.Equals(Addresses, person.Addresses);
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(Name, Addresses);
    }
}

public class Address
{ 
    public string StreetName { get; set; }

    public override bool Equals(object? obj)
    {
        return obj is Address address &&
               StreetName == address.StreetName;
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(StreetName);
    }
}

测试代码

var person = new Person() 
{
        Name = "Mr Test", 
        Addresses = new List<Address>()
        {
            new Address()
            {
                StreetName = "Test Street" 
            }
        }
};

var person2 = new Person()
{
    Name = "Mr Test",
    Addresses = new List<Address>()
        {
            new Address()
            {
                StreetName = "Test Street"
            }
        }
};

var result = person.Equals(person2); // 此处result为false

问题原因

问题出在List<Address>的比较逻辑上:List<T>的默认相等性比较(EqualityComparer<List<Address>>.Default.Equals)是引用比较——它只会检查两个List是否指向同一个内存对象,不会逐个对比集合内元素的内容是否相等。即使你已经正确重写了Address的Equals方法,默认List比较也不会调用它来判断元素相等性。


解决方案

要正确比较集合内的元素,需要使用SequenceEqual方法(来自System.Linq命名空间),它会逐个遍历两个序列的元素,并调用元素类型的Equals方法判断单个元素是否相等。同时要处理集合为null的边界情况,避免空引用异常。

修改后的完整代码如下:

using System.Linq;

public class Person
{ 
    public string Name { get; set; }
    public List<Address> Addresses { get; set; }

    public override bool Equals(object? obj)
    {
        // 同一引用直接返回相等
        if (ReferenceEquals(this, obj)) return true;
        // 类型不符或为null返回不等
        if (obj is not Person person) return false;
        
        // 比较Name属性
        if (Name != person.Name) return false;
        
        // 处理Addresses为null的情况
        if (Addresses == null && person.Addresses == null) return true;
        if (Addresses == null || person.Addresses == null) return false;
        
        // 逐个比较集合内的Address元素
        return Addresses.SequenceEqual(person.Addresses);
    }

    public override int GetHashCode()
    {
        // 先计算Name的哈希值
        var hash = Name?.GetHashCode() ?? 0;
        
        // 累加每个Address的哈希值到总哈希中
        if (Addresses != null)
        {
            foreach (var address in Addresses)
            {
                hash = HashCode.Combine(hash, address?.GetHashCode() ?? 0);
            }
        }
        
        return hash;
    }
}

public class Address
{ 
    public string StreetName { get; set; }

    public override bool Equals(object? obj)
    {
        if (ReferenceEquals(this, obj)) return true;
        if (obj is not Address address) return false;
        
        return StreetName == address.StreetName;
    }

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

修改说明

  1. Person.Equals方法:增加了引用相等判断、null值处理,改用SequenceEqual实现集合元素的内容比较。
  2. Person.GetHashCode方法:不再直接使用List的引用哈希,而是基于Name和每个Address的哈希值组合生成,保证内容相同的对象哈希值一致,符合GetHashCode的规范。

修改后运行原测试代码,result会返回true。

内容的提问来源于stack exchange,提问作者Mark D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 10:14:58