如何从数据库返回的自定义对象IEnumerable构建无重复HashSet?
按自定义对象Id去重构建HashSet的完整方案
刚好遇到过类似的场景,要实现基于IEnumerable<Question>构建不含重复元素的HashSet<Question>(按Id属性去重),核心是正确实现自定义的相等比较器——默认情况下HashSet会用对象的引用地址判断是否重复,这显然不符合你的需求。
1. 先明确Question类结构
先给出典型的Question类示例(你可以根据实际业务调整属性):
public class Question { public int Id { get; set; } // 作为去重依据的唯一标识属性 // 其他无关属性示例 public string Title { get; set; } public string Content { get; set; } public DateTime CreateTime { get; set; } }
2. 实现自定义相等比较器QuestionComparer
我们需要实现IEqualityComparer<Question>接口,告诉HashSet如何判断两个Question对象是否属于重复元素:
public class QuestionComparer : IEqualityComparer<Question> { // 判断两个Question是否相等:仅对比Id属性 public bool Equals(Question x, Question y) { // 处理null边界情况 if (ReferenceEquals(x, y)) return true; if (x == null || y == null) return false; // 核心逻辑:Id相同则视为重复对象 return x.Id == y.Id; } // 生成哈希码:基于Id属性,确保相同Id的对象哈希码一致 public int GetHashCode(Question obj) { // 避免null引用异常 return obj?.Id.GetHashCode() ?? 0; } }
这里要注意:
GetHashCode的实现必须和Equals逻辑完全匹配——如果两个对象通过Equals判断为相等,它们的GetHashCode必须返回相同的值,否则HashSet的去重逻辑会失效。
3. 完整的业务代码实现
结合你提供的数据库查询逻辑,完整的去重代码如下:
// 初始化带有自定义比较器的HashSet,确保后续添加元素时按Id自动去重 HashSet<Question> results = new HashSet<Question>(new QuestionComparer()); // 从数据库异步查询获取Question集合 var queryResults = await query.ExecuteNextAsync<Question>(); // 将查询结果合并到HashSet中,自动跳过已存在的重复元素 results.UnionWith(queryResults);
额外优化选项
如果你有权修改Question类的代码,也可以直接重写类本身的Equals和GetHashCode方法,这样就不需要额外的比较器,直接初始化HashSet<Question>即可:
public class Question { public int Id { get; set; } // 其他属性... public override bool Equals(object obj) { if (obj is Question other) { return Id == other.Id; } return false; } public override int GetHashCode() { return Id.GetHashCode(); } }
这种方式更简洁,但如果Question类是第三方库或者不能修改的类,还是用自定义比较器的方案更灵活。
内容的提问来源于stack exchange,提问作者Luki
相关产品推荐
相关产品推荐

