ConcurrentDictionary不止一次添加相同的键

时间:2015-01-17 02:00:49

标签: c# dictionary concurrency parallel-processing concurrentdictionary

我想使用ConcurrentDictionary检查之前是否已添加此数据密钥,但看起来我仍然可以添加之前添加的密钥。

代码:

    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>();

测试代码:

    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);

结果:

true
true

1 个答案:

答案 0 :(得分:3)

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

一种选择是将您的类型设为struct而不是class。这使用默认比较,该比较将考虑字段值。

或者,您可以继续覆盖GetHashCode()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;
    }
}

注意:

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

有关其他指导,请参阅General advice and guidelines on how to properly override object.GetHashCode()