【问题标题】:Can I use GetHashCode without Equals?我可以使用不带 Equals 的 GetHashCode 吗?
【发布时间】:2020-04-04 20:34:39
【问题描述】:

也许我有些不明白。不,我绝对不明白一些事情。有一个具有两个 int 类型属性的自定义类。覆盖 GetHashCode 方法,我想使用这两个属性作为获取哈希码的基础。但是,由于 GetHashCode 方法的返回类型是 int,而我的类中的两个属性都是 int。事实证明,我的属性的各种值的组合会比int类型所能容纳的还要多。结果,无论如何,我都会发生碰撞。正确的? 此外,我想说的是,我尝试了几种被标记为可接受答案的算法,这些算法来自其他主题,其中包括 Jon Skeet 等权威人士提供了他们的选择,但仍然发生冲突。

    public class Equivalent
    {
        public Equivalent(int a, int b)
        {
            A = a;
            B = b;
        }

        public int A { get; }
        public int B { get; }

        public override int GetHashCode()
        {
            var vals = new[]
            {
                A.GetHashCode(),
                B.GetHashCode()
            };

            var hash1 = (5381 << 16) + 5381;
            var hash2 = hash1;

            var i = 0;
            foreach (var hashCode in vals)
            {
                if (i % 2 == 0)
                    hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ hashCode;
                else
                    hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ hashCode;

                ++i;
            }

            return hash1 + (hash2 * 1566083941);
        }

        public override string ToString()
        {
            return $"{A};{B}";
        }
    }

    public void GetHash()
    {
        var len = 1000000;
        var d = new Dictionary<int, Equivalent>();
        for (var i = 0; i < len; i++)
        {
            var eq = new Equivalent(
                _r.Next(int.MinValue, int.MaxValue),
                _r.Next(int.MinValue, int.MaxValue));

            var hash = eq.GetHashCode();
            if (d.TryGetValue(hash, out var saved))
            {
                File.AppendAllText("result2.csv", $"{hash};{saved}\n");
                File.AppendAllText("result2.csv", $"{hash};{eq}\n");
                continue;
            }

            d.Add(hash, eq);
            Thread.Sleep(1);
        }
    }

【问题讨论】:

  • 您能添加更多有用的标签,以便其他人更容易找到这个问题吗?
  • 哈希码不是对象的唯一标识符;允许两个不相等的对象具有相同的哈希码。肯定会发生碰撞。
  • 您的问题到底是什么?
  • @JimMischel 我的问题是哈希码是否适合识别对象。显然不是。

标签: c# hash gethashcode hash-collision


【解决方案1】:

我怀疑您正在尝试将GetHashCode 用于不适合的用途。 查看this SO answer 了解更多背景信息。

我不完全确定我理解 if (d.TryGetValue(hash, out var saved)) 背后的意图 - 我假设您想检查您是否已经将此特定行保存到您的 CSV 中。如果确实如此,您可能会发现维护 HashSet 更容易,因为它基本上掩盖了您的 int 键,同时允许您检查唯一性:

    for (var i = 0; i < len; i++)
    {
        var eq = new Equivalent(
            _r.Next(int.MinValue, int.MaxValue),
            _r.Next(int.MinValue, int.MaxValue));

        if(!d.Contains(eq))
        {
            //File.AppendAllText("result2.csv", $"{hash};{saved}\n"); // do you need this line?
            File.AppendAllText("result2.csv", $"{eq.GetProperSha1Hash()};{eq}\n");//you will need to implement the method, but there's plenty examples
            d.Add(eq);
            continue;
        }
        Thread.Sleep(1);
    }

【讨论】:

  • 感谢您的示例。您提供链接的答案很有用。我需要您注释掉的行来比较收到相同哈希码的对象的内容。 if (d.TryGetValue(hash, out var saved)) 这可能是为了安全起见。我可以在我的示例中使用 Equals 方法来验证识别对象的第二步吗?好吧,我什么时候才能得到两个相同的哈希值。
  • 我在您的示例中没有看到 Equals 实现,但是是的,这是规定的方法:您同时实现 EqualsGetHashCode 并让“字典”(或“哈希集” ) 做它的魔法。为了让生活更轻松,我会使用像 Resharper 这样的工具为我生成平等成员。
猜你喜欢
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多