gpt4 book ai didi

c# - object.GetHashCode()可以在不同的机器上为相同的对象(字符串)产生不同的结果吗?

转载 作者:太空狗 更新时间:2023-10-29 17:40:40 27 4
gpt4 key购买 nike

当在不同的机器上调用时,是否有可能和一个对象(尤其是string或任何原始或非常简单的类型(如struct))产生不同的.GetHashCode()方法值?

例如,表达式"Hello World".GetHashCode()是否有可能在不同的机器上产生不同的值。我主要是要求C#.NET,但我想这可能适用于Java甚至其他语言吗?

编辑:

正如下面的答案和评论所指出的,我知道.GetHashCode()可以被覆盖,并且不能保证它在框架的不同版本之间产生的结果。因此,重要的是要弄清楚我的心意是简单的类型(无法继承,因此将GetHashCode()覆盖),并且我在所有机器上都使用相同版本的框架。

最佳答案

简短的回答:是的。

但是简短的答案不好玩,是吗?

在实现GetHashCode()时,必须确保以下几点:

When GetHashCode() is called on another object that should be considered equal to this, in this App Domain, the same value will be returned.



就是这样。您确实需要尝试做一些事情(尽可能多地传播与非相等对象有关的内容,但不要花太长时间以至于它首先要超过哈希的所有好处)和您的代码如果您不这样做,它会很烂,但实际上并不会破坏。如果您不走那么远,它将破裂,因为例如:
dict[myObj] = 3;
int x = dict[myObj];//KeyNotFoundException

好的。如果我正在实现 GetHashCode(),为什么我可以做得比这更进一步,为什么我不能呢?

首先,我为什么不呢?

也许这是程序集的一个稍微不同的版本,我在两次构建之间进行了改进(或至少尝试过)。

也许一个是32位的,另一个是64位的,我一直在追求效率,并为每种效率选择了不同的算法以利用不同的字长(这并不是闻所未闻的,尤其是在对诸如集合或字符串之类的对象进行哈希处理时) 。

在决定什么构成“相等”对象时,我可能要考虑的某些因素本身在系统之间会以这种方式变化。

也许我实际上是故意引入了具有不同内部版本的其他种子,以捕获任何同事错误地依赖我的哈希码的情况! (我听说过MS使用 string.GetHashCode()的实现来做到这一点,但不记得我是从可信的还是可信的来源听到的)。

不过,主要是这是前两个原因之一。

现在,为什么我要提供这样的保证?

如果我这样做,很可能是偶然的。如果可以仅基于单个整数id来比较元素的相等性,那么这就是我将用作哈希码的内容。如果哈希值不太好,其他任何事情都会做得更多。我不太可能改变这一点,所以我可能会改变。

我之所以会这样做的另一个原因是,我要保证自己。无话可说,我无能为力。

好吧,让我们开始一些实际的事情。在某些情况下,您可能需要与机器无关的保证。在某些情况下,您可能想要相反的情况,稍后我会介绍。

首先,检查您的逻辑。你能应付碰撞吗?好,那我们就开始吧。

如果这是您自己的类,请实现以提供此类保证,将其记录下来,然后就可以完成了。

如果不是您的类(class),则以提供它的方式实现 IEqualityComparer<T>。例如:
public class ConsistentGuaranteedComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
if(obj == null)
return 0;
int hash = obj.Length;
for(int i = 0; i != obj.Length; ++i)
hash = (hash << 5) - hash + obj[i];
return hash;
}
}

然后使用它代替内置的哈希码。

在一个有趣的情况下,我们可能想要相反的情况。如果我可以控制要散列的字符串集,那么我可以选择一堆具有相同散列码的字符串。您基于散列的集合的性能会更糟,并且非常糟糕。我可能会继续以比您更快的速度执行此操作,因此这可能是拒绝服务攻击。发生这种情况的情况并不多,但重要的是,如果您要处理我发送的XML文档,而不能仅仅排除某些元素(许多格式允许其中的元素自由)。然后,解析器中的 NameTable将受到伤害。在这种情况下,我们每次都会创建一个新的哈希机制:
public class RandomComparer : IEqualityComparer<string>
{
private int hashSeed = Environment.TickCount;
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
if(obj == null)
return 0;
int hash = hashSeed + obj.Length;
for(int i = 0; i != obj.Length; ++i)
hash = hash << 5 - hash + obj[i];
hash += (hash << 15) ^ 0xffffcd7d;
hash ^= (hash >>> 10);
hash += (hash << 3);
hash ^= (hash >>> 6);
hash += (hash << 2) + (hash << 14);
return hash ^ (hash >>> 16)
}
}

在给定的用法中这将是一致的,但在每次使用之间是不一致的,因此攻击者无法构造输入来强制将其变为DoSsed。顺便说一句, NameTable不使用 IEqualityComparer<T>,因为它想要处理具有索引和长度的char数组,除非必要,否则无需构造字符串,但是它做了类似的事情。

顺便说一句,在Java中,指定了 string的哈希码并且不会更改,但是其他类可能不是这种情况。

编辑:对上面的 ConsistentGuaranteedComparer中采用的方法的整体质量进行了一些研究,我对在答案中使用这种算法不再感到满意;虽然它用来描述概念,但分布却不尽人意。当然,如果已经实现了这样的事情,那么就不能在不违反保证的情况下进行更改,但是如果我现在建议使用 this library of mine, written after said research,如下所示:
public class ConsistentGuaranteedComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
return obj.SpookyHash32();
}
}

上面的 RandomComparer的效果还不错,但也可以改进:
public class RandomComparer : IEqualityComparer<string>
{
private int hashSeed = Environment.TickCount;
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
return obj.SpookyHash32(hashSeed);
}
}

或更难以预测的:
public class RandomComparer : IEqualityComparer<string>
{
private long seed0 = Environment.TickCount;
private long seed1 = DateTime.Now.Ticks;
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
return obj.SpookyHash128(seed0, seed1).GetHashCode();
}
}

关于c# - object.GetHashCode()可以在不同的机器上为相同的对象(字符串)产生不同的结果吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8838053/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com