Kum*_*mba 24 vb.net gethashcode
所以我试图弄清楚如何GetHashCode()在VB中正确覆盖大量的自定义对象.一些搜索引导我得到这个美妙的答案.
除了有一个问题:VB缺少.NET 4.0中的checked和unchecked关键字.据我所知,无论如何.因此,使用乔恩斯基特的实现,我想对具有三个主要成员一个相当简单的类创建这样一个覆盖:Name As String,Value As Int32,和[Type] As System.Type.因此,我提出:
Public Overrides Function GetHashCode() As Int32
Dim hash As Int32 = 17
hash = hash * 23 + _Name.GetHashCode()
hash = hash * 23 + _Value
hash = hash * 23 + _Type.GetHashCode()
Return hash
End Function
Run Code Online (Sandbox Code Playgroud)
问题:即使像这样的简单对象,Int32也太小了.我测试的特定实例将"Name"作为一个简单的5个字符的字符串,并且该哈希值足够接近Int32的上限,当它试图计算哈希值(Value)的第二个字段时,它会溢出.因为我找不到粒度checked/ unchecked支持的VB等价物,所以我无法解决这个问题.
我也不想删除整个项目中的Integer溢出检查.这个东西可能...... 40%完成(我做了,TBH),我有更多的代码要写,所以我需要这些溢出检查很长一段时间.
GetHashCode对于VB和Int32 ,Jon的版本的"安全"版本是什么?或者,.NET 4.0 在某个地方有checked/ unchecked我在MSDN上很难找到吗?
编辑:
根据链接的SO问题,最底层的一个不受欢迎的答案提供了一个准解决方案.我说准,因为它感觉像是......作弊.乞丐不能选择,对吧?
从C#转换为更易读的VB并与上述对象(Name,Value,Type)对齐,我们得到:
Public Overrides Function GetHashCode() As Int32
Return New With { _
Key .A = _Name, _
Key .B = _Value, _
Key .C = _Type
}.GetHashCode()
End Function
Run Code Online (Sandbox Code Playgroud)
这会触发编译器显然通过生成匿名类型来"欺骗",然后它会在项目命名空间之外编译,可能会禁用整数溢出检查,并允许数学发生并在溢出时简单地回绕.它似乎也涉及box操作码,我知道它是性能命中.但是,没有取消装箱.
但这提出了一个有趣的问题.无数次,我已经看到它在这里和其他地方声明VB和C#都生成相同的IL代码.这显然不是100%的情况......就像使用C#的 </修辞-问题>unchecked关键字只会导致不同的操作码被发出.那么为什么我还要继续看到两者都产生完全相同的IL不断重复的假设?
无论如何,我宁愿找到一个可以在每个对象模块中实现的解决方案.从ILDASM的角度来看,必须为我的每一个对象创建匿名类型都会变得混乱.当我说我在项目中实施了很多课程时,我不是在开玩笑.
EDIT2:我确实在MSFT Connect上打开了一个错误,VB PM结果的要点是他们会考虑它,但不要屏住呼吸:https:
//connect.microsoft.com/VisualStudio/反馈/信息/ 636564 /签未选中的关键字,在视觉,基本
快速浏览.NET 4.5的变化表明他们还没有考虑过,所以也许.NET 5?
我的最终实现符合GetHashCode的约束,同时对于VB来说仍然是快速且独特的,从此页面上的"旋转哈希"示例中得出:
'// The only sane way to do hashing in VB.NET because it lacks the
'// checked/unchecked keywords that C# has.
Public Const HASH_PRIME1 As Int32 = 4
Public Const HASH_PRIME2 As Int32 = 28
Public Const INT32_MASK As Int32 = &HFFFFFFFF
Public Function RotateHash(ByVal hash As Int64, ByVal hashcode As Int32) As Int64
Return ((hash << HASH_PRIME1) Xor (hash >> HASH_PRIME2) Xor hashcode)
End Function
Run Code Online (Sandbox Code Playgroud)
我也认为"Shift-Add-XOR"哈希也可能适用,但我还没有测试过.
Han*_*ant 23
使用Long可以避免溢出:
Dim hash As Long = 17
'' etc..
Return CInt(hash And &H7fffffffL)
Run Code Online (Sandbox Code Playgroud)
And运算符确保不会抛出溢出异常.然而,这确实在计算的哈希码中失去了一点"精度",结果总是正的.VB.NET没有内置函数来避免它,但你可以使用一个技巧:
Imports System.Runtime.InteropServices
Module NoOverflows
Public Function LongToInteger(ByVal value As Long) As Integer
Dim cast As Caster
cast.LongValue = value
Return cast.IntValue
End Function
<StructLayout(LayoutKind.Explicit)> _
Private Structure Caster
<FieldOffset(0)> Public LongValue As Long
<FieldOffset(0)> Public IntValue As Integer
End Structure
End Module
Run Code Online (Sandbox Code Playgroud)
现在你可以写:
Dim hash As Long = 17
'' etc..
Return NoOverflows.LongToInteger(hash)
Run Code Online (Sandbox Code Playgroud)
这是一个结合Hans Passant答案和Jon Skeet答案的实现.
它甚至可以用于数百万个属性(即没有整数溢出异常)并且非常快(对于具有1,000,000个字段的类生成哈希代码少于20毫秒,对于只有100个字段的类几乎不可测量).
这是处理溢出的结构:
<StructLayout(LayoutKind.Explicit)>
Private Structure HashCodeNoOverflow
<FieldOffset(0)> Public Int64 As Int64
<FieldOffset(0)> Public Int32 As Int32
End Structure
Run Code Online (Sandbox Code Playgroud)
还有一个简单的GetHashCode函数:
Public Overrides Function GetHashCode() As Integer
Dim hashCode As HashCodeNoOverflow
hashCode.Int64 = 17
hashCode.Int64 = CLng(hashCode.Int32) * 23 + Field1.GetHashCode
hashCode.Int64 = CLng(hashCode.Int32) * 23 + Field2.GetHashCode
hashCode.Int64 = CLng(hashCode.Int32) * 23 + Field3.GetHashCode
Return hashCode.Int32
End Function
Run Code Online (Sandbox Code Playgroud)
或者如果您愿意:
Public Overrides Function GetHashCode() As Integer
Dim hashCode = New HashCodeNoOverflow With {.Int32 = 17}
For Each field In Fields
hashCode.Int64 = CLng(hashCode.Int32) * 23 + field.GetHashCode
Next
Return hashCode.Int32
End Function
Run Code Online (Sandbox Code Playgroud)
我在vb.net中实现Skeet先生的解决方案时遇到了同样的问题.我最终使用Mod运算符到达那里.每个Mod by Integer.MaxValue应该只返回到该点的最不重要的组件,并且将始终在Integer.MaxValue和Integer.MinValue中 - 这应该与未选中的效果相同.你可能没有像我那样经常修改(只有当它有可能变得比一个长的大(这意味着要结合很多哈希码)然后一次结束时),但是这个的一个变种对我来说(并且让你玩一些像其他散列函数一样使用更大的素数而不用担心).
Public Overrides Function GetHashCode() As Int32
Dim hash as Int64 = 17
hash = (hash * 23 + _Name.GetHashCode()) Mod Integer.MaxValue
hash = (hash * 23 + _Value) Mod Integer.MaxValue
hash = (hash * 23 + _Type.GetHashCode()) Mod Integer.MaxValue
Return Convert.ToInt32(hash)
End Function
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7094 次 |
| 最近记录: |