如何根据对象的内容为对象生成唯一的哈希码?

Con*_*ngo 17 .net c# hash .net-4.0 visual-studio-2010

我需要根据对象的内容为对象生成唯一的哈希码,例如DateTime(2011,06,04)应该等于DateTime(2011,06,04).

  • 我不能使用.GetHashCode(),因为它可能会为具有不同内容的对象生成相同的哈希代码.
  • 我无法使用ObjectIDGenerator中的.GetID,因为它为具有相同内容的对象生成不同的哈希码.
  • 如果对象包含其他子对象,则需要以递归方式检查这些对象.
  • 它需要处理集合.

我需要写这个的原因?我正在使用PostSharp编写缓存层.

更新

我想我可能一直在问错误的问题.正如Jon Skeet指出的那样,为了安全起见,我需要在缓存键中使用尽可能多的唯一组合,因为对象中存在潜在数据的组合.因此,最好的解决方案可能是使用反射构建一个长字符串,该字符串对对象的公共属性进行编码.对象不是太大,所以这是非常快速和有效的:

  • 它有效地构造缓存键(只需将对象的公共属性转换为大字符串).
  • 它有效地检查缓存命中(比较两个字符串).

Eri*_*ert 36

来自评论:

我喜欢基于对象内容的GUID之类的东西.我不介意每10万亿亿亿年左右偶尔会出现重复

这似乎是一个不寻常的要求,但由于这是你的要求,让我们做数学.

让我们假设你每年制作十亿个独特的物品 - 每秒30个 - 达10万亿亿亿亿年.这是您正在创建的10 49个唯一对象.计算数学很容易; 当散列的比特大小小于384时,该时间中至少一个散列冲突的概率高于10 18中的一个.

因此,您至少需要一个384位哈希码才能获得所需的唯一性级别.这是一个方便的大小,12个int32s.如果你每秒要制作30个以上的物体,或者想要的概率小于10 18,那么就需要更多的比特.

为什么你有这么严格的要求?

如果我有你声明的要求,我会怎么做.第一个问题是将每个可能的数据转换为自描述的比特序列.如果您已经有序列化格式,请使用它.如果没有,请创建一个可以序列化您感兴趣的所有可能散列对象的对象.

然后,要散列对象,将其序列化为字节数组,然后通过SHA-384或SHA-512散列算法运行字节数组.这将产生一个专业的加密等级384或512位哈希,即使面对试图强迫碰撞的攻击者,它也被认为是独一无二的.在你的10万亿亿亿亿年的时间框架内,这么多位应该足以确保低碰撞概率.


Jon*_*eet 16

如果你需要创建一个唯一的哈希码,那么你基本上是在谈论一个可以代表你的类型可以拥有的状态的数字.对于DateTime不是意味着花蜱值和DateTimeKind,我相信.

您可以假设该Ticks属性的前两位将为零,并使用它们来存储该类型.这意味着,就我所知,你可以直到7307年:

private static ulong Hash(DateTime when)
{
    ulong kind = (ulong) (int) when.Kind;
    return (kind << 62) | (ulong) when.Ticks;
}
Run Code Online (Sandbox Code Playgroud)

  • 偏离主题,但对于它的价值你可以使用内置的[`ToBinary`](http://msdn.microsoft.com/en-us/library/system.datetime.tobinary.aspx)和[`FromBinary `](http://msdn.microsoft.com/en-us/library/system.datetime.frombinary.aspx)在`DateTime`和`long`之间序列化/反序列化的方法(封装`Kind`和`Ticks` ). (2认同)
  • 你怎么会得到一个32位的价值? (2认同)

Bro*_*ass 11

你不是在谈论哈希代码,你需要一个代表你的状态的数字 - 因为它是唯一的,它可能必须非常大,这取决于你的对象结构.

我需要写这个的原因?我正在使用PostSharp编写缓存层.

为什么不使用常规哈希码,并通过实际比较对象来处理冲突?这似乎是最合理的方法.

  • 打败我.:)使用一些超级哈希代码无法解决问题.使用更正常的哈希码,当找到匹配时,使用Equals()来检查它们是否真的相同. (2认同)