在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
相关产品推荐
相关产品推荐

