it-swarm-ko.tech

두 문자열을 서로 바꿀 수있을 때 두 문자열로 구조에 대해 GetHashCode를 구현하는 방법

C #에 구조가 있습니다.

public struct UserInfo
{
   public string str1
   {
     get;
     set;
   }

   public string str2
   {
     get;
     set;
   }   
}

유일한 규칙은 UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))

이 구조에 대해 GetHashCode 함수를 재정의하는 방법은 무엇입니까?

66
Graviton

MSDN :

해시 함수에는 다음 속성이 있어야합니다.

  • 두 객체가 동일하게 비교되는 경우 각 객체에 대한 GetHashCode 메서드는 동일한 값을 반환해야합니다. 그러나 두 개체가 동일하게 비교되지 않으면 두 개체의 GetHashCode 메서드가 다른 값을 반환하지 않아도됩니다.
  • 객체의 GetHashCode 메서드의 반환 값을 결정하는 객체 상태가 수정되지 않는 한 객체의 Equals 메서드는 동일한 해시 코드를 일관되게 반환해야합니다. 이는 현재 응용 프로그램 실행에 대해서만 적용되며 응용 프로그램을 다시 실행하면 다른 해시 코드가 반환 될 수 있습니다.
  • 최상의 성능을 얻으려면 해시 함수가 모든 입력에 대해 무작위 분포를 생성해야합니다.

올바른 방법을 고려하면 다음과 같습니다.

return str1.GetHashCode() ^ str2.GetHashCode() 

^는 다른 정류 연산으로 대체 될 수 있습니다.

66
aku

Jon Skeet의 답변 -^는 좋지 않습니다. 종종 충돌 해시를 생성합니다!

26
Tomáš Kafka
public override int GetHashCode()
{
    unchecked
    {
        return (str1 ?? String.Empty).GetHashCode() +
            (str2 ?? String.Empty).GetHashCode();
    }
}

명시 적으로 ( 'AA', 'BB') 및 ( 'BB', 'AA')를 명시 적으로 동일하게 원하지만 '+'연산자를 사용하는 것이 '^'를 사용하는 것보다 낫습니다. 'AA', 'AA') 및 ( 'BB', 'BB')는 동일해야합니다 (또는 해당 문제에 대해 모두 동일한 쌍).

Null의 경우 빈 문자열에서 알려진 상수를 즉시 반환하지 않고 'GetHashCode ()'를 수행하기 때문에 '가능한 한 빨리'규칙을 완전히 준수하지는 않지만 명시 적으로 측정하지 않아도 널을 많이 기대하지 않으면 그 차이가 걱정할 정도로 크지 않을 것이라는 추측을 위험에 빠뜨리기 위해.

15
Jerry
  1. 일반적으로 클래스에 대한 해시 코드를 생성하는 간단한 방법은 XOR 해시 코드 생성에 참여할 수있는 모든 데이터 필드입니다. UserInfo ( "AA", "BB") 및 UserInfo ( "BB", "AA")의 해시 코드가 동일해야한다는 (인공적?) 요구 사항도 충족합니다.

  2. 클래스 사용에 대한 가정을 할 수 있다면 해시 함수를 향상시킬 수 있습니다. 예를 들어, str1과 str2가 동일한 것이 일반적인 경우 XOR은 좋은 선택이 아닐 수 있습니다. 그러나 str1과 str2가 이름과 성을 나타내는 경우 XOR는 아마도 좋은 선택 일 것입니다.

비록 이것이 실제적인 예는 아니지만, 다음과 같은 점을 지적 할 가치가 있습니다 :-이것은 아마도 구조체의 사용에 대한 좋지 않은 예일 것입니다 : 구조체는 일반적으로 가치 의미론을 가져야합니다. 여기에 사건. -setter와 함께 속성을 사용하여 해시 코드를 생성하는 것도 문제를 요구합니다.

5
Joe

간단한 general 방법은 다음과 같습니다.

return string.Format("{0}/{1}", str1, str2).GetHashCode();

엄격한 성능 요구 사항이 없으면 이것이 내가 생각할 수있는 가장 쉬운 방법이며 복합 키가 필요할 때이 방법을 자주 사용합니다. 그것은 null 경우를 잘 처리하고 (m) 해시 충돌을 일으키지 않습니다 (일반적으로). 문자열에 '/'가 필요하면 예상하지 못한 다른 구분 기호를 선택하십시오.

4
Daniel Lidström

ReSharper가 제안하는 내용은 다음과 같습니다.

public int GetHashCode()
{
    unchecked
    {
        int hashCode;

        // String properties
        hashCode = (hashCode * 397) ^ (str1!= null ? str1.GetHashCode() : 0);
        hashCode = (hashCode * 397) ^ (str2!= null ? str1.GetHashCode() : 0);

        // int properties
        hashCode = (hashCode * 397) ^ intProperty;
        return hashCode;
    }
}

397은 결과 변수가 오버플로되어 해시 비트를 약간 혼합하여 해시 코드를 더 잘 분배 할 수있는 충분한 크기의 소수입니다. 그렇지 않으면 397에는 같은 크기의 다른 소수와 구별되는 특별한 것이 없습니다.

3
Jani Hyytiäinen
public override int GetHashCode()   
{       
    unchecked      
    {           
        return(str1 != null ? str1.GetHashCode() : 0) ^ (str2 != null ? str2.GetHashCode() : 0);       
    }   
}
3
user11556

Gary Shutler가 지적했듯이 아.

return str1.GetHashCode() + str2.GetHashCode();

넘칠 수 있습니다. Artem이 제안한대로 캐스팅을 시도하거나 선택하지 않은 키워드로 명령문을 둘러 쌀 수 있습니다.

return unchecked(str1.GetHashCode() + str2.GetHashCode());
2
Grokys

이것을 시도하십시오 :

(((long)str1.GetHashCode()) + ((long)str2.GetHashCode())).GetHashCode()
1
Artem Tikhomirov

많은 가능성. 예 :.

return str1.GetHashCode() ^ str1.GetHashCode()

0
VolkerK

아마도 str1.GetHashCode () + str2.GetHashCode ()와 같은 것입니까? 또는 (str1.GetHashCode () + str2.GetHashCode ())/2? 이렇게하면 str1과 str2가 바뀌 었는지 여부에 관계없이 동일합니다 ...

0
Mike Stone

정렬 한 다음 연결하십시오.

 반환 ((str1.CompareTo (str2) <1)? str1 + str2 : str2 + str1) 
 .GetHashCode (); 
0
Steve Morgan

GetHashCode의 결과는 다음과 같습니다.

  1. 최대한 빨리.
  2. 가능한 한 독특합니다.

사람들을 염두에두고 다음과 같이 갈 것입니다.

if (str1 == null)
    if (str2 == null)
        return 0;
    else
       return str2.GetHashCode();
else
    if (str2 == null)
        return str1.GetHashCode();
    else
       return ((ulong)str1.GetHashCode() | ((ulong)str2.GetHashCode() << 32)).GetHashCode();

편집 : 널을 잊어 버렸습니다. 코드가 수정되었습니다.

0
Omer van Kloeten