如何在C#中正确比较Street与StandardStreet复杂对象
判断Street与StandardStreet相等的最优实现
需求说明
当Street的名称等于StandardStreet的名称,或是StandardStreet的任意同义词名称时,判定两者相等,同时要保证Contains方法能正常工作(Contains依赖对象的Equals实现)。
现有代码问题
- 强制将
obj转换为Street,传入其他BaseStreet子类会抛出异常 BaseStreet无CityId属性,属于代码笔误- 未重写
GetHashCode,导致集合类(如HashSet、List)的Contains无法正确工作(哈希码不匹配会直接判定不相等) - 类型判断过于严格(
obj.GetType() != typeof(BaseStreet)),子类实例传入会直接返回false
正确实现方案
1. 修正StandardStreet的Equals与GetHashCode
public class StandardStreet : BaseStreet { public HashSet<SynonymStreet> SynonymStreets { get; set; } = new HashSet<SynonymStreet>(); public override bool Equals(object? obj) { // 空值直接返回false if (obj is null) return false; // 引用相同直接判定相等 if (ReferenceEquals(this, obj)) return true; // 非BaseStreet子类直接返回false if (obj is not BaseStreet otherStreet) return false; // 处理Street类型的匹配逻辑 if (obj is Street street) { // 匹配自身名称或同义词名称,可根据业务调整大小写规则 return Name.Equals(street.Name, StringComparison.OrdinalIgnoreCase) || SynonymStreets.Any(s => s.Name.Equals(street.Name, StringComparison.OrdinalIgnoreCase)); } // 处理StandardStreet自身的相等判断 if (obj is StandardStreet standardStreet) { return Id == standardStreet.Id || Name.Equals(standardStreet.Name, StringComparison.OrdinalIgnoreCase); } // 其他BaseStreet子类默认按名称判断 return Name.Equals(otherStreet.Name, StringComparison.OrdinalIgnoreCase); } public override int GetHashCode() { // 基于名称生成哈希码,保证相等对象的哈希码一致,大小写规则与Equals保持一致 return Name?.GetHashCode(StringComparison.OrdinalIgnoreCase) ?? 0; } }
2. 可选:实现Street的反向相等判断
如果需要支持Street.Equals(StandardStreet)的对称判断,在Street类中重写Equals:
public class Street : BaseStreet { public override bool Equals(object? obj) { if (obj is null) return false; if (ReferenceEquals(this, obj)) return true; // 调用StandardStreet的Equals逻辑,保证对称性 if (obj is StandardStreet standardStreet) { return standardStreet.Equals(this); } return base.Equals(obj); } public override int GetHashCode() { return Name?.GetHashCode(StringComparison.OrdinalIgnoreCase) ?? 0; } }
3. 使用Contains示例
// 构造StandardStreet集合 var standardStreets = new List<StandardStreet> { new StandardStreet { Name = "中山路", SynonymStreets = new HashSet<SynonymStreet> { new SynonymStreet { Name = "中山大道" } } } }; // 待匹配的Street var targetStreet = new Street { Name = "中山大道" }; // 使用Contains判断是否匹配 bool isMatched = standardStreets.Contains(targetStreet); // 返回true
内容的提问来源于stack exchange,提问作者Ruslan Karamurzanov
相关产品推荐
相关产品推荐

