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

在C#中为何两个CustomBomComponent对象调用.Equals()不相等?

问题分析与解决方案

默认情况下,引用类型的Equals方法比较的是对象的引用地址,而非属性内容。所以即使两个CustomBomComponent对象的所有属性值完全一致,只要不是同一个实例,oma.Equals(cma)就会返回false。Null值可能会影响部分属性的比较结果,但核心原因是你没有重写Equals来实现内容比较。

要解决这个问题,需要重写Equals和GetHashCode方法,同时处理Null值、嵌套对象以及集合的比较逻辑:

完整实现代码

using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Linq;

namespace Config_TestCases.Entities
{
    [Serializable]
    [XmlRoot("BomComponents")]
    public class CustomBomComponent
    {
        [XmlElement(Order = 1)]
        public string ComponentName { get; set; }

        [XmlElement(Order = 2)]
        public BomMaterialAttributes BomMaterialAttributes { get; set; }

        [XmlArray(ElementName = "BomMaterials", Order = 3)]
        [XmlArrayItem(ElementName = "BomMaterial")]
        public List<CustomBomMaterial> BOMMaterials { get; set; }

        [XmlArray(ElementName = "BomComponents", Order = 4)]
        [XmlArrayItem(ElementName = "BomComponent")]
        public List<CustomBomComponent> BomComponents { get; set; }

        public override bool Equals(object obj)
        {
            // 同一引用直接返回true
            if (ReferenceEquals(this, obj)) return true;
            // 对象为null或类型不匹配返回false
            if (obj is null || GetType() != obj.GetType()) return false;
            
            var other = (CustomBomComponent)obj;
            
            // 逐个比较属性,处理Null情况
            bool componentNameEqual = string.Equals(ComponentName, other.ComponentName, StringComparison.Ordinal);
            bool attributesEqual = Equals(BomMaterialAttributes, other.BomMaterialAttributes);
            bool materialsEqual = CompareLists(BOMMaterials, other.BOMMaterials);
            bool componentsEqual = CompareLists(BomComponents, other.BomComponents);
            
            return componentNameEqual && attributesEqual && materialsEqual && componentsEqual;
        }

        public override int GetHashCode()
        {
            // 组合各属性哈希值,符合Equals与GetHashCode的契约
            int hash = ComponentName?.GetHashCode() ?? 0;
            hash = hash * 31 + (BomMaterialAttributes?.GetHashCode() ?? 0);
            hash = hash * 31 + GetListHashCode(BOMMaterials);
            hash = hash * 31 + GetListHashCode(BomComponents);
            return hash;
        }

        // 辅助方法:比较两个List<T>的内容是否完全一致(含顺序)
        private bool CompareLists<T>(List<T> list1, List<T> list2)
        {
            if (list1 is null && list2 is null) return true;
            if (list1 is null || list2 is null) return false;
            if (list1.Count != list2.Count) return false;
            
            return list1.Zip(list2, (item1, item2) => Equals(item1, item2)).All(b => b);
        }

        // 辅助方法:计算List<T>的哈希值
        private int GetListHashCode<T>(List<T> list)
        {
            if (list is null) return 0;
            int hash = 17;
            foreach (var item in list)
            {
                hash = hash * 31 + (item?.GetHashCode() ?? 0);
            }
            return hash;
        }
    }
}

关键注意事项

  • 必须确保BomMaterialAttributes和CustomBomMaterial类也重写了Equals和GetHashCode方法,否则嵌套对象仍会使用引用比较,导致结果不准确。
  • 如果需要忽略字符串大小写,可以将StringComparison.Ordinal替换为StringComparison.OrdinalIgnoreCase。
  • 若集合顺序不影响相等性(如无序集合),需修改CompareLists方法,改为比较元素是否完全相同(不考虑顺序)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 22:04:58