【问题标题】:.Net Hash Codes no longer persistent?.Net 哈希码不再持久?
【发布时间】:2009-10-14 10:53:46
【问题描述】:

我有一个 API,其中各种类型都有自定义哈希码。这些散列码基于获取所讨论对象的字符串表示的散列。使用了各种加盐技术,以使哈希码尽可能不冲突,并且具有等效字符串表示的不同类型的对象具有不同的哈希码。

显然,由于哈希码是基于字符串的,因此存在一些冲突(无限字符串与 32 位整数的有限范围)。我使用基于字符串表示的哈希值,因为我需要哈希值在会话中持续存在,尤其是在对象的数据库存储中使用。

今天突然间,我的代码开始为对象生成不同的哈希码,这会破坏各种事情。它今天早些时候工作了,我没有接触过任何涉及哈希码生成的代码。

我知道 .Net 文档允许在 .Net 框架版本(以及 32 位和 64 位版本之间)更改哈希码,但我没有更改框架版本,也没有框架更新据我所知,最近

任何想法,因为这看起来真的很奇怪?

编辑

哈希码生成如下:

//Compute Hash Code
this._hashcode = 
   (this._nodetype + this.ToString() + PlainLiteralHashCodeSalt).GetHashCode();

【问题讨论】:

  • 因为它看起来有点简单,只是作为评论:对象已移动到不同的命名空间,您将对象的完全限定名称用于哈希。这样您就不必触摸代码,只需移动对象即可。
  • 字符串表示不是基于类型名称,而是基于对象值的字符串表示
  • 我也检查了 SVN,所有具有自定义哈希码的类型的文件都没有完全改变
  • 您是否尝试过恢复到旧版本?

标签: c# .net hashcode


【解决方案1】:

StampedeXV 在他的评论中建议的是,如果 ToString() 未被覆盖,Object.ToString() 将默认返回完全限定名称。

  1. 如果ToString() 未被覆盖,更改命名空间(或类名)将更改此值。
  2. 显然,覆盖 ToString() 会改变它。
  3. 准确检查_nodeType 的修改方式和位置。
  4. PlainLiteralHashCodeSalt 仍然是一个谜(我认为它是一个常量字符串)。
  5. 没有人保证String.HashCode() 不会改变,所以您至少可以使用Reflector 来获取方法的源代码并将其包含在您的库中。这不是我通常会推荐的,但你不想在未来依赖它。

不用说,您应该跟踪所有 3 个值(_nodeType、th​​is.ToString() 和 salt string)以检查它们是否没有更改。如果您可以恢复到有效的旧版本,那么您已经成功了一半。

除此之外,不建议保留哈希码。如果这与性能相关,请注意您的数据库负责处理索引和散列。而且由于您不能保证它是唯一的,因此它也不是 GUID。那还有什么意义呢?

但由于它已经在数据库中,您现在主要关心的是如何取回 HashCode 实现。

【讨论】:

  • 它与性能相关,我知道与之相关的风险,但结合持久性方法的其他方面,它在性能差异上产生了显着的数量级。节点类型在基础构造函数中分配一次,PlainLiteralHashCodeSalt 是一个常量字符串
  • 接受了答案,因为在调查事情后我意识到问题在于我使用的是一个旧数据库,该数据库在我更改哈希码生成(几个月前)之前已经填充这就是为什么哈希码看起来无效的原因,即当时用于这三件事的值不同(撞到桌子上)
【解决方案2】:

您说您使用此哈希码进行持久化。这对您当前的实现来说是个坏主意,因为您使用 ToString() 函数来生成哈希码。此函数的结果与持久性无关,可能开发人员出于 GUI 设计或其他原因需要对其进行更改而忘记了,它也用于持久性。
在你的情况下,我会看看 ToString() 方法的结果,也许它改变了。这可以通过改变文化或将对象移动到另一个命名空间来发生 - 看看吧,也许你会找到原因。

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 2011-06-19
    • 1970-01-01
    • 2015-01-06
    • 2017-04-06
    • 1970-01-01
    • 2016-03-10
    • 2017-06-21
    • 1970-01-01
    相关资源
    最近更新 更多