byte []数组上的GetHashCode()

Che*_*riy 52 c# hash

GetHashCode()byte[]数组上调用时计算什么?具有相同内容的2个数据阵列不提供相同的散列.

Jon*_*eet 58

.NET中的数组不会覆盖EqualsGetHashCode,因此您将获得的值基本上基于引用相等(即默认实现Object) - 对于值相等,您需要滚动自己的代码(或从第三个中找到一些派对).IEqualityComparer<byte[]>如果您尝试将字节数组用作字典中的键等,则可能需要实现.

编辑:这是一个可重用的数组相等比较器,只要数组元素适当地处理相等,它应该没问题.请注意,在将数组用作字典中的键后,不得改变该数组,否则您将无法再次找到它 - 即使使用相同的引用也是如此.

using System;
using System.Collections.Generic;

public sealed class ArrayEqualityComparer<T> : IEqualityComparer<T[]>
{
    // You could make this a per-instance field with a constructor parameter
    private static readonly EqualityComparer<T> elementComparer
        = EqualityComparer<T>.Default;

    public bool Equals(T[] first, T[] second)
    {
        if (first == second)
        {
            return true;
        }
        if (first == null || second == null)
        {
            return false;
        }
        if (first.Length != second.Length)
        {
            return false;
        }
        for (int i = 0; i < first.Length; i++)
        {
            if (!elementComparer.Equals(first[i], second[i]))
            {
                return false;
            }
        }
        return true;
    }

    public int GetHashCode(T[] array)
    {
        unchecked
        {
            if (array == null)
            {
                return 0;
            }
            int hash = 17;
            foreach (T element in array)
            {
                hash = hash * 31 + elementComparer.GetHashCode(element);
            }
            return hash;
        }
    }
}

class Test
{
    static void Main()
    {
        byte[] x = { 1, 2, 3 };
        byte[] y = { 1, 2, 3 };
        byte[] z = { 4, 5, 6 };

        var comparer = new ArrayEqualityComparer<byte>();

        Console.WriteLine(comparer.GetHashCode(x));
        Console.WriteLine(comparer.GetHashCode(y));
        Console.WriteLine(comparer.GetHashCode(z));
        Console.WriteLine(comparer.Equals(x, y));
        Console.WriteLine(comparer.Equals(x, z));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 关于`GetHashCode`是否应扫描整个序列似乎[某些争论](http://stackoverflow.com/a/468084/1149773).有趣的是,`Array.IStructuralEquatable.GetHashCode`的[内部实现](http://referencesource.microsoft.com/#mscorlib/system/array.cs,807)只考虑数组的最后八项,牺牲了哈希唯一性速度. (2认同)

mqp*_*mqp 20

与其他非原始内置类型一样,它只返回任意内容.它肯定不会尝试散列数组的内容.看到这个答案.


ric*_*fox 12

byte[]继承GetHashCode()object,它不会覆盖它.所以你得到的基本上object是实现.


Dan*_*yuk 8

简单的解决方案

    public static int GetHashFromBytes(byte[] bytes)
    {
        return new BigInteger(bytes).GetHashCode();
    }
Run Code Online (Sandbox Code Playgroud)

  • 看到这个解决方案让我微笑。干净、优雅。深入挖掘哈希实现最终会调用 https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/NumericsHelpers.cs#L272 (2认同)
  • 同意,但这通常是散列所固有的。这就像去dictionary.com 抱怨某个词的定义一样。 (2认同)
  • 请注意,此方法会生成整个字节数组的副本,因此可能效率不高。另外,理解 GetHashCode() 的目的也很重要 - 它并不是为了产生唯一的值,而是为了在 Dictionary 或 HashSet 中分配存储桶而生成一个分布良好的值,这得益于每个存储桶大小大致相等。两种类型都使用 GetHashCode() 和 Equals() 的组合来确定是否确实发生了冲突。 (2认同)

n00*_*099 6

如果您使用 .NET 6 或至少 .NET Core 2.1,则可以使用System.HashCode结构编写更少的代码并获得更好的性能。

使用.NET 6 中提供的方法HashCode.AddBytes() :

public int GetHashCode(byte[] value)
{
    var hash = new HashCode();
    hash.AddBytes(value);
    return hash.ToHashCode();
}
Run Code Online (Sandbox Code Playgroud)

使用.NET Core 2.1 中提供的方法HashCode.Add :

public int GetHashCode(byte[] value) =>
    value.Aggregate(new HashCode(), (hash, i) => {
        hash.Add(i);
        return hash;
    }).ToHashCode();
Run Code Online (Sandbox Code Playgroud)

请注意,在HashCode.AddBytes()的文档中它说:

此方法不保证添加字节范围的结果与单独添加相同字节的结果相匹配。

在这个Sharplab 演示中,它们只是输出相同的结果,但这可能因 .NET 版本或运行时环境而异。