2

I want to use ConcurrentDictionary to check if this data key has been added before, but it looks like I can still add keys which added before.

code:

    public class pKeys
    {
        public pKeys()
        { }
        public pKeys(long sID, long pID)
        {
            this.seID = sID;
            this.pgID = pID;

        }
        public long seID;
        public long pgID;
    }

    public static ConcurrentDictionary<pKeys, bool> existenceDic 
= new ConcurrentDictionary<pKeys, bool>();

test code:

    pKeys temKey = new pKeys(111, 222);
    bool res = existenceDic.TryAdd(temKey, true);
    Console.WriteLine(res);

    temKey = new pKeys(111, 222);
    res = existenceDic.TryAdd(temKey, true);
    Console.WriteLine(res);

result:

true
true
4

1 回答 1

3

您可以添加两个包含相同值的不同实例,因为您没有覆盖GetHashCode()Equals()。这会导致使用默认的相等比较,对于引用类型,它只是比较引用本身。在这种情况下,两个不同的实例总是被视为不同的值。

一种选择是使您的类型 astruct而不是class. 这使用将考虑字段值的默认比较。

或者,您可以继续覆盖GetHashCode()and Equals()。例如:

public class pKeys
{
    public pKeys()
    { }
    public pKeys(long sID, long pID)
    {
        this.seID = sID;
        this.pgID = pID;

    }
    public readonly long seID;
    public readonly long pgID;

    public override int GetHashCode()
    {
        return seID.GetHashCode() * 37 + pgID.GetHashCode();
    }

    public override bool Equals(object other)
    {
        pKeys otherKeys = other as pKeys;

        return otherKeys != null &&
            this.seID == otherKeys.seID &&
            this.pgID == otherKeys.pgID;
    }
}

笔记:

  • 哈希码是根据各个值的哈希码计算的。1 乘以 37,这只是一个方便的素数;有些人更喜欢使用更大的素数来更好地“混合”。对于大多数情况,以上将正常工作恕我直言。
  • 请注意,您提出的解决方案,将值转换为字符串,将它们连接起来,并返回其哈希码有几个负面的方面:
    • 您必须创建三个字符串实例才能生成哈希码!单独的内存开销已经足够糟糕了,但当然还有格式化两个整数的成本。
    • 从字符串生成哈希码在计算上比从整数值更昂贵
    • 您发生碰撞的风险要高得多,因为不同的值更容易产生相同的字符串(例如 (11, 2222) 和 (111, 222))
  • 我添加readonly到你的领域。如果您决定将类型设为 a (即即使您不覆盖方法),这将是至关重要的。struct但即使对于一个类,可相等的可变类型也是一个大问题,因为如果它们在添加到基于散列的集合后发生更改,则该集合实际上被破坏了。在此处使用readonly可确保类型是不可变的。(此外,恕我直言,应该避免公共字段,但如果必须拥有它们,readonly即使您不覆盖相等方法,它们也绝对应该存在)。
  • 有些人喜欢在方法中检查确切的类型相等性Equals()。事实上,这通常是一个好主意……它简化了比较对象的场景并使代码更易于维护。但是为了举例,可分配性(即as)更容易阅读,并且无论如何在许多情况下都是有效的。

请参阅有关如何正确覆盖 object.GetHashCode() 的一般建议和指南以获取更多指导。

于 2015-01-17T03:49:18.053 回答