programing

선택/선택 해제된 키워드 지원 없이 VB에서 GetHashCode를 재정의하시겠습니까?

javamemo 2023. 5. 20. 00:24
반응형

선택/선택 해제된 키워드 지원 없이 VB에서 GetHashCode를 재정의하시겠습니까?

그래서 저는 어떻게 해야만 정확하게 오버라이드를 할 수 있는지 알아내려고 노력하고 있습니다.GetHashCode()사용자 지정 개체 수가 많은 경우 VB로 표시됩니다.약간의 탐색은 저를 이 멋진 대답으로 이끌었습니다.

단 한 가지 문제가 있습니다. VB는 두 가지 모두를 가지고 있지 않습니다.checked그리고.unchecked 4입니다.NET 4.0의 키워드입니다.어쨌든 제가 볼 때는.Skeet의하여 3개의 구성원으로 를 만들어 .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의 상한에 가까웠습니다. 해시의 두 번째 필드(값)를 계산하려고 할 때 오버플로가 발생했습니다.granular 세된화 VB에해 VB를에 수 입니다.checked/unchecked지원, 저는 이 문제를 해결할 수 없습니다.

또한 전체 프로젝트에서 정수 오버플로 검사를 제거하고 싶지 않습니다.이건 아마..40% 완료(제가 작성한 TBH), 작성해야 할 코드가 훨씬 더 많기 때문에 상당 기간 오버플로 검사가 필요합니다.

요?GetHashCodeVB 및 Int32용 버전?또는 .NET 4.0은 다음과 같은 기능하지 않습니다.checked/uncheckedMSDN에서 쉽게 찾을 수 없는 어딘가에?



연결된 SO 질문에 따르면 맨 아래에 있는 사랑받지 못하는 답변 중 하나가 준 해결책을 제공했습니다.제가 준말을 하는 이유는 그게.. 사기치는 것처럼 느껴지기 때문입니다.하지만 거지가 선택할 수는 없잖아요, 그렇죠?

C#에서 보다 읽기 쉬운 VB로 변환하고 위에서 설명한 개체(이름, 값, 유형)에 맞게 조정하면 다음과 같은 이점을 얻을 수 있습니다.

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%가 아닙니다.C#의 사용처럼 unchecked 키워드는 단순히 다른 opcode를 내보냅니다. 그렇다면 왜 두 가지 모두 정확히 같은 IL을 생산한다는 가정이 계속 반복되는 것일까요?   </어법적-질문>

어쨌든 각 객체 모듈 내에서 구현할 수 있는 솔루션을 찾고 싶습니다.모든 개체에 대해 익명 유형을 만들어야 하는 것은 ILDASM의 관점에서 볼 때 지저분하게 보일 것입니다.저는 제 프로젝트에 많은 수업이 시행되고 있다고 말하는 것이 농담이 아닙니다.


에디트2: MSFT 커넥트에서 버그를 열었는데, VBPM의 결과의 요지는 그들이 고려할 것이지만, 숨을 쉬지는 말라는 것이었습니다. 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" 해시도 적용될 수 있다고 생각하지만, 저는 그것을 테스트하지 않았습니다.

오버플로를 방지하려면 Long을 사용합니다.

Dim hash As Long = 17
'' etc..
Return CInt(hash And &H7fffffffL)

And 연산자는 오버플로 예외가 발생하지 않도록 합니다.그러나 계산된 해시 코드에서 "정밀도"가 1비트 손실되므로 결과는 항상 긍정적입니다. 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)

다음은 한스 패상의 답변과 스키트답변을 결합한 구현입니다.

수백만 개의 속성(즉, 정수 오버플로 예외 없음)에도 작동하며 매우 빠릅니다(1,000,000개의 필드가 있는 클래스에 대해 해시 코드를 생성하는 데 20ms 미만, 100개의 필드만 있는 클래스에 대해서는 거의 측정할 수 없습니다).

오버플로를 처리하는 구조는 다음과 같습니다.

<StructLayout(LayoutKind.Explicit)>
Private Structure HashCodeNoOverflow
    <FieldOffset(0)> Public Int64 As Int64
    <FieldOffset(0)> Public Int32 As Int32
End Structure

간단한 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

또는 원하는 경우:

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

저는 vb.net 에서 Skeet 씨의 솔루션을 구현하는 데 동일한 문제를 겪었습니다.저는 결국 모드 연산자를 사용하여 그곳에 도착했습니다.각 Mod by 정수.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

과 C#을 하여 적합한 해시 도우미를 할 수 있습니다.unchecked전체 프로젝트에 대한 의 키워드 또는 전환 오버플로 검사(VB.NET 및 C# 프로젝트 모두에서 가능).당신이 원한다면 당신은 사용할 수 있습니다.ilmerge이 어셈블리를 기본 어셈블리에 병합합니다.

선택/선택 해제된 키워드 지원 없이 VB에서 GetHashCode를 재정의하는 향상된 응답?

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

각 곱셈 후에 트리밍이 있습니다.정수 인수를 사용하는 And 연산자는 상위 바이트를 0으로 설정하지 않으므로 리터럴은 명시적으로 Long으로 정의됩니다.

에게 VB와 같은 것을 에.unchecked그리고 잠시 격노(c#dev 지금은 vb를 하고 있음), 저는 한스 패상이 올린 것에 가까운 솔루션을 구현했습니다.실습니다 . 끔찍한 공연형편없는 공연.이것은 분명히 한스가 게시한 솔루션이 아니라 제 구현 때문이었습니다.저는 돌아가서 그의 해결책을 더 자세히 복사할 수 있었습니다.

하지만 저는 다른 해결책으로 문제를 해결했습니다.을 하는 글uncheckedVB 언어 기능 요청 페이지에서 이미 프레임워크에 있는 해시 알고리즘을 사용하는 아이디어를 제공했습니다.의 문제로, 저는 문서에나, 는내제가 .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를 쓸 수밖에 없는 다른 가난한 개발자들에게 유용하기를 바랍니다.

건배.

또한 RemoveIntegerChecksMsBuild 속성이 VB 컴파일러 속성에영향을 미쳐 컴파일러가 런타임 검사를 내보내지 못한다는 것을 발견했습니다.

  <PropertyGroup>
    <RemoveIntegerChecks>true</RemoveIntegerChecks>   
  </PropertyGroup>

언급URL : https://stackoverflow.com/questions/4654227/overriding-gethashcode-in-vb-without-checked-unchecked-keyword-support

반응형