locked
Rewritting C# GetHashCode in Visual Basic with a few Questions RRS feed

  • Question

  • User686339638 posted

    Hello,

    I found the following code online, but i don't know the Visual Basic equivalent.  I found some pieces but i'm not sure i understand it.

    // Note: Not quite FNV!
    public override int GetHashCode()
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = (int) 2166136261;
            // Suitable nullity checks etc, of course :)
            hash = hash * 16777619 ^ field1.GetHashCode();
            hash = hash * 16777619 ^ field2.GetHashCode();
            hash = hash * 16777619 ^ field3.GetHashCode();
            return hash;
        }
    }

    Found here: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode

    I reformatted this code in VB below to correct for the lack of a unchecked method 

    Public Overrides Function GetHashCode() As Integer
     
       Dim hash As Long = 17
       hash = hash * 16777619 ^ If(IsNothing(field1), 1, field1.GetHashCode())
       hash = hash * 16777619 ^ If(IsNothing(field2), 1, field2.GetHashCode())
       hash = hash * 16777619 ^ If(IsNothing(field3), 1, field3.GetHashCode())
     
       Return CInt(hash And &H7FFFFFFFL)
    End Function

    I got part of this from: http://stackoverflow.com/questions/4654227/overriding-gethashcode-in-vb-without-checked-unchecked-keyword-support

    Few Questions:

    1) Is this written correctly?

    2) What does And &H7FFFFFFFL do? I don't understand this.

    3) Why choose 2166136261 over 17 for the initial Long value? It seems that the longer number will reach Arithmetic Overflow a lot quicker than using smaller numbers such as 17. Is there an advantage?

    Thanks very much! 

    Thursday, March 10, 2016 10:01 PM

Answers

  • User614698185 posted

    Hi JacobPressures,

    If you want to use GetHashCode method, please refer to the below link:

    https://documentation.devexpress.com/#CodeRush/CustomDocument17203

    Best Regards,

    Candice Zhou

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, March 16, 2016 9:42 AM
  • User686339638 posted

    Thanks for the link Candice!  Ok the following 2 code samples were overflowing on the Long int.

    Public Overrides Function GetHashCode() As Integer
                
                Dim hash As Long = 2166136261 
    
    
                hash = hash * 16777619 Xor If(IsNothing(PayerID), 1, PayerID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(CaseID), 1, CaseID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    Public Overrides Function GetHashCode() As Integer
    
                Dim hash As Long = 2166136261 
    
                hash = hash * 16777619 + If(IsNothing(PayerID), 1, PayerID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(CaseID), 1, CaseID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    I purposely used these numbers to test if they overflowed.

    While i did not understand everything discussed in that link, I was able to get this much out, which does not overflow:

    Public Overrides Function GetHashCode() As Integer
    
                Dim hash As Long = 2166136261 
    
                hash = CInt((hash * 16777619 Xor If(IsNothing(PayerID), 1, PayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(CaseID), 1, CaseID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())) And &H7FFFFFFFL)
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    Public Overrides Function GetHashCode() As Integer
                
                Dim hash As Long = 2166136261 
    
                hash = CInt((hash * 16777619 + If(IsNothing(PayerID), 1, PayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(CaseID), 1, CaseID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())) And &H7FFFFFFFL)
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    Since the two above did not overflow, I assume the smaller numbers should certainly  be safe.

    So here is the code I ended up using. 

    Public Overrides Function GetHashCode() As Integer
                
                Dim hash As Long = 17
    
                hash = CInt((hash * 23 + If(IsNothing(PayerID), 1, PayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(CaseID), 1, CaseID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())) And &H7FFFFFFFL)
    
                Return CInt(hash And &H7FFFFFFFL)
    End Function

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, March 17, 2016 7:05 PM

All replies

  • User397347636 posted

    The '^' symbol in C# is the exclusive or operator - the equivalent in VB is 'XOr'.

    "And &H7FFFFFFL" is a bitwise 'And' operation.

    Friday, March 11, 2016 12:35 AM
  • User614698185 posted

    Hi JacobPressures,

    hash = hash * 16777619 ^ field1.GetHashCode();

    As David Anton said, The '^' symbol in C# is the exclusive or operator - the equivalent in VB is 'XOr':

    hash = hash * 16777619 Xor field1.GetHashCode()

    2) What does And &H7FFFFFFFL do? I don't understand this.

    If you calculate hash as Long, but then return it as Integer with Return CInt(hash And &H7FFFFFFFL). This way could avoid the overflow.

    Best Regards,

    Candice Zhou

    Friday, March 11, 2016 5:24 AM
  • User686339638 posted

    Thanks very much guys. One last question:

    3) Why choose 2166136261 over 17 for the initial Long value? It seems that the longer number will reach Arithmetic Overflow a lot quicker than using smaller numbers such as 17. Is there an advantage?

    Candice, you said in answer to #2: "If you calculate hash as Long, but then return it as Integer with Return CInt(hash And &H7FFFFFFFL). This way could avoid the overflow."

    So does that mean that the size of the integers being multiplied doesn't matter? Should i still avoid the overflow perhaps because of degradation of precision or quality?

    Thanks a lot guys!

    Friday, March 11, 2016 2:53 PM
  • User686339638 posted

    This did not work. It resulted in an overflow.  I'm not sure that code is working right.

    Tuesday, March 15, 2016 3:04 PM
  • User614698185 posted

    Hi JacobPressures,

    If you want to use GetHashCode method, please refer to the below link:

    https://documentation.devexpress.com/#CodeRush/CustomDocument17203

    Best Regards,

    Candice Zhou

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, March 16, 2016 9:42 AM
  • User686339638 posted

    Thanks for the link Candice!  Ok the following 2 code samples were overflowing on the Long int.

    Public Overrides Function GetHashCode() As Integer
                
                Dim hash As Long = 2166136261 
    
    
                hash = hash * 16777619 Xor If(IsNothing(PayerID), 1, PayerID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(CaseID), 1, CaseID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())
                hash = hash * 16777619 Xor If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    Public Overrides Function GetHashCode() As Integer
    
                Dim hash As Long = 2166136261 
    
                hash = hash * 16777619 + If(IsNothing(PayerID), 1, PayerID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(CaseID), 1, CaseID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())
                hash = hash * 16777619 + If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    I purposely used these numbers to test if they overflowed.

    While i did not understand everything discussed in that link, I was able to get this much out, which does not overflow:

    Public Overrides Function GetHashCode() As Integer
    
                Dim hash As Long = 2166136261 
    
                hash = CInt((hash * 16777619 Xor If(IsNothing(PayerID), 1, PayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(CaseID), 1, CaseID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 Xor If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())) And &H7FFFFFFFL)
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    Public Overrides Function GetHashCode() As Integer
                
                Dim hash As Long = 2166136261 
    
                hash = CInt((hash * 16777619 + If(IsNothing(PayerID), 1, PayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(CaseID), 1, CaseID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 16777619 + If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())) And &H7FFFFFFFL)
    
                Return CInt(hash And &H7FFFFFFFL)  
    End Function

    Since the two above did not overflow, I assume the smaller numbers should certainly  be safe.

    So here is the code I ended up using. 

    Public Overrides Function GetHashCode() As Integer
                
                Dim hash As Long = 17
    
                hash = CInt((hash * 23 + If(IsNothing(PayerID), 1, PayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(InsuredPersonID), 1, InsuredPersonID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(CaseID), 1, CaseID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(PersonPayerID), 1, PersonPayerID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(AppointmentID), 1, AppointmentID.GetHashCode())) And &H7FFFFFFFL)
                hash = CInt((hash * 23 + If(IsNothing(EncounterID), 1, EncounterID.GetHashCode())) And &H7FFFFFFFL)
    
                Return CInt(hash And &H7FFFFFFFL)
    End Function

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, March 17, 2016 7:05 PM