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

C#中Dictionary使用实体类作为key时如何判断键是否存在

问题原因

C# 中默认的引用类型(class)的相等性比较逻辑是比较内存地址,你每次循环都new Psukim()生成新实例,哪怕所有属性值完全一致,两个实例的内存地址不同,Dictionary调用默认的Equals和GetHashCode判定时就会认为是完全不同的键,所以ContainsKey始终返回false。

解决方案

有三种常用实现方式,按需选择即可:

方案1:重写Psukim类的Equals和GetHashCode方法

直接修改Psukim类的定义,自定义相等性比较逻辑,示例代码如下:

public class Psukim
{
    public int Book { get; set; }
    public int Pasuk { get; set; }
    public int Perek { get; set; }

    public override bool Equals(object obj)
    {
        if (obj is Psukim other)
        {
            return Book == other.Book && Pasuk == other.Pasuk && Perek == other.Perek;
        }
        return false;
    }

    public override int GetHashCode()
    {
        // 组合三个属性的哈希值,C# 7.0+ 支持该写法
        return HashCode.Combine(Book, Pasuk, Perek);
        // 低版本C#可以用替换为下面的写法
        // return Book.GetHashCode() ^ Pasuk.GetHashCode() ^ Perek.GetHashCode();
    }
}

方案2:将Psukim改为record类型(C# 9.0+ 推荐)

C# 9 引入的record类型默认实现了值语义的相等性比较,只要所有属性值相等就判定为两个实例相等,修改成本极低:

// 直接把class关键字改成record即可
public record Psukim
{
    public int Book { get; set; }
    public int Pasuk { get; set; }
    public int Perek { get; set; }
}
// 也可以用更简洁的主构造函数写法
public record Psukim(int Book, int Pasuk, int Perek);

方案3:自定义相等比较器(无法修改Psukim类源码时使用)

如果不能改动Psukim类的代码,可以自定义IEqualityComparer<Psukim>,在初始化Dictionary时传入比较器即可:

// 自定义比较器
public class PsukimEqualityComparer : IEqualityComparer<Psukim>
{
    public bool Equals(Psukim x, Psukim y)
    {
        if (x == null || y == null) return false;
        return x.Book == y.Book && x.Pasuk == y.Pasuk && x.Perek == y.Perek;
    }

    public int GetHashCode(Psukim obj)
    {
        return HashCode.Combine(obj.Book, obj.Pasuk, obj.Perek);
    }
}

// 初始化Dictionary时传入自定义比较器
Dictionary<Psukim, List<int>> showPsukim = new Dictionary<Psukim, List<int>>(new PsukimEqualityComparer());

额外优化建议

你现有代码里判断ContainsKey之后又取一次值,会执行两次字典查找,可以用TryGetValue简化逻辑,提升性能:

foreach (var item in allPsukim)
{
    Psukim newPasuk = new Psukim()
    {
        Book = item.Book,
        Pasuk = item.Pasuk,
        Perek = item.Perek
    };

    if (showPsukim.TryGetValue(newPasuk, out var posList))
    {
        posList.Add(item.Position);
    }
    else
    {
        showPsukim.Add(newPasuk, new List<int> { item.Position });
    }
}

内容的提问来源于stack exchange,提问作者R-S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:45:02