Поэтому я пытаюсь выяснить, как правильно переопределить GetHashCode()
в VB для большого количества пользовательских объектов.Немного поиска приводит меня к этому замечательному ответу .
За исключением одной проблемы: в VB отсутствует ключевое слово checked
и unchecked
в .NET 4.0.Насколько я могу сказать, в любом случае.Поэтому, используя реализацию Джона Скита, я попытался создать такое переопределение для довольно простого класса, который имеет три основных члена: 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
Проблема: Int32 слишком мал даже для простого объекта, такого как этот.В конкретном экземпляре, который я тестировал, «Имя» представляло собой простую 5-символьную строку, и один этот хеш был достаточно близок к верхнему пределу Int32, поэтому при попытке вычислить второе поле хеша (Значение) он переполнился.Поскольку я не могу найти VB-эквивалент для гранулярной поддержки checked
/ unchecked
, я не могу обойти это.
Я также не хочу удалять проверки переполнения целых чисел во всем проекте.Возможно, эта штука завершена на 40% (я это придумал, TBH), и у меня есть гораздо больше кода, чтобы написать, поэтому мне нужны эти проверки переполнения в течение достаточно долгого времени.
Чтобудет «безопасной» версией Jon GetHashCode
для VB и Int32?Или в .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
Это запускает компилятор, по-видимому, в «обман», генерируя анонимный тип, который затем компилируется вне пространства имен проекта, предположительно с отключенными целочисленными проверками переполнения, и позволяет выполнять математику и просто переносить ее при переполнении.Кажется, он также включает в себя box
кодов операций, которые, как я знаю, являются хитами производительности.Но без распаковки.
Но это поднимает интересный вопрос.Бесчисленное количество раз я видел, как здесь и в других местах говорится, что и VB, и C # генерируют один и тот же код IL.Это явно не так в 100% случаев ... Как и использование ключевого слова unchecked
в C #, просто вызывает другой код операции.Так почему же я продолжаю видеть предположение, что оба производят один и тот же IL, повторяется?
В любом случае, я бы предпочел найти решение, которое может быть реализовано в каждом объектном модуле.Необходимость создания анонимных типов для каждого из моих объектов будет выглядеть беспорядочно с точки зрения ILDASM.Я не шучу, когда говорю, что в моем проекте реализовано много классов. EDIT2: Я открыл ошибку в MSFT Connect, и суть результата от VB PM заключалась в том, что они его рассмотрят, но не затаили дыхание: https://connect.microsoft.com/VisualStudio/feedback/details/636564/checked-unchecked-keywords-in-visual-basic
Беглый взгляд на изменения в .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
Я также думаю, что "Shift-Add-XOR"Хеш может также применяться, но я не проверял это.