да indeedy. В особенности Вы видите проблемы с "кучей" отладки/выпуска, являющейся отличающимся, также если Ваша библиотека будет использовать новое размещение, или какая-либо пользовательская "куча", то у Вас будет проблема. Проблема Отладки/Выпуска безусловно наиболее распространена все же.
Используйте Long, чтобы избежать переполнения:
Dim hash As Long = 17
'' etc..
Return CInt(hash And &H7fffffffL)
Оператор 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
Теперь вы можете написать:
Dim hash As Long = 17
'' etc..
Return NoOverflows.LongToInteger(hash)
Улучшенный ответ Переопределение GetHashCode в VB без поддержки отмеченных / непроверенных ключевых слов?
Public Overrides Function GetHashCode() as Integer
Dim hashCode as Long = 0
If myReplacePattern IsNot Nothing Then _
hashCode = ((hashCode*397) Xor myField.GetHashCode()) And &HffffffffL
If myPattern IsNot Nothing Then _
hashCode = ((hashCode*397) Xor myOtherField.GetHashCode()) And &HffffffffL
Return CInt(hashCode)
End Function
После каждого умножения происходит обрезка. И литерал определен явно как Long, потому что оператор And с аргументом Integer не обнуляет старшие байты.
После исследования того, что VB не дал нам ничего подобного unchecked
, и немного рассерженного (c # dev сейчас делает vb), я реализовал решение, близкое к тому, которое написал Ханс Пассант. Я потерпел неудачу в этом. Ужасная производительность. Это, безусловно, было связано с моей реализацией, а не с решением, опубликованным Хансом. Я мог бы вернуться и более внимательно скопировать его решение.
Однако я решил проблему с другим решением. Сообщение с жалобой на отсутствие unchecked
на странице запросов возможностей языка VB дало мне идею использовать алгоритм хэширования уже в рамках. В моей задаче у меня были String
и Guid
, которые я хотел использовать для словарного ключа. Я решил, что Tupple(Of Guid, String)
будет хорошим внутренним хранилищем данных.
Оригинальная плохая версия
Public Structure HypnoKey
Public Sub New(name As String, areaId As Guid)
_resourceKey = New Tuple(Of Guid, String)(resourceAreaId, key)
End Sub
Private ReadOnly _name As String
Private ReadOnly _areaId As Guid
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Public ReadOnly Property AreaId As Guid
Get
Return _areaId
End Get
End Property
Public Overrides Function GetHashCode() As Integer
'OMFG SO BAD
'TODO Fail less hard
End Function
End Structure
Значительно улучшенная версия
Public Structure HypnoKey
Public Sub New(name As String, areaId As Guid)
_innerKey = New Tuple(Of Guid, String)(areaId , key)
End Sub
Private ReadOnly _innerKey As Tuple(Of Guid, String)
Public ReadOnly Property Name As String
Get
Return _innerKey.Item2
End Get
End Property
Public ReadOnly Property AreaId As Guid
Get
Return _innerKey.Item1
End Get
End Property
Public Overrides Function GetHashCode() As Integer
Return _innerKey.GetHashCode() 'wow! such fast (enuf)
End Function
End Structure
Итак, хотя я ожидаю, что есть гораздо лучшие решения, чем это я очень счастлив. У меня хорошее выступление. Кроме того, неприятный код утилиты исчез. Надеюсь, что это полезно для некоторых других бедных разработчиков, вынужденных написать VB, который сталкивается с этим постом.
Ура