2012-09-26 3 views
0

this question here을 읽음으로써 this article here으로 이어진다.내 추상 기본 클래스의 모든 확장에 사용할 기본 GetHashCode()를 구현할 수 있습니까?

나는 추상적 인 기본 클래스를 가지고 있는데,이를 통해 추상적 인 기본 클래스 (기본 다형성)를 확장하는 클래스 만 수락하도록 메서드를 제한 할 수 있습니다. 내 질문은 : GetHashCode() 내 구체적인 기본 구현에 대한 구현을위한 적절한 재정의를 제공하기 위해 구현할 수 있습니까? (즉 각 구상 클래스에 GetHashCode()을 무시 방지 할 수 있습니다.) 나는이 같은 내 추상 기본 클래스 뭔가 방법을 상상하고있어

:

public abstract class FooBase 
{ 
    private static readonly int prime_seed = 13; 
    private static readonly int prime_factor = 7; 

    public override int GetHashCode() 
    { 
     // Seed using the hashcode for this concrete class' Type so 
     // two classes with the same properties return different hashes. 
     int hash = prime_seed * this.GetType().GetHashCode(); 
     // Get this concrete class' public properties. 
     var props = this.GetType().GetProperties(BindingFlags.Public); 
     foreach (var prop in props) 
     { 
      // Factor in each of this concrete class' public properties' hashcodes. 
      hash = (hash * prime_factor) + prop.GetHashCode(); 
     } 
     return hash; 
    } 
} 

이 몇 가지 기본적인 평등의 단위 테스트하지만 난에서 작동하는 것 같다을 내가 뭔가를 간과 한 것 같은 느낌. 컴파일러를 피하기 위해 각 구체적인 클래스에서 재정의를 제공해야합니다. GetHashCode()를 재정의하지 말고 경고해야합니다.하지만 적어도이 방법을 사용하면 각 클래스에 대한 구현을 수동으로 작성하지 않아도됩니다.

+0

은 해시 반영에 시간이 걸릴 것 같습니다. –

+0

다음은 GetHashCode() 및 Equals()의 구현 및 사용에 대한 내용과 서로의 관계에 대해 더 자세히 설명했습니다. 더 나은 이해를 얻은 후에 위의 작업 중 GetHashCode() 기본 코드를 파기했습니다. 그 오래된 NBC 공익 광고들 중 하나를 큐에 넣으십시오 : 더 많이 알기를 ... – JMD

+0

'structs'에서'GetHashCode()'를 오버라이드시키는 것이 항상 좋은 이유 중 하나는 이것과 같은 일반적인 아이디어를 사용하는 디폴트를 피하는 것입니다. 대부분의 경우 작동하지만, 1 분 안에 코딩 할 수있는 가장 간단한'GetHashCode()'오버라이드보다 훨씬 느립니다. –

답변

2

이 수행하는 것보다 더 나은 :

public override int GetHashCode() 
{ 
    return 1; 
} 

해시 함수에 대한 키는 계산이 빨라야한다. 리플렉션을 사용하면 해시를 통해 얻을 수있는 모든 이점을 잃을 수 있습니다.

벤치 마크 할 가치가 있습니다.

또한 Equals가 true를 반환하면 해시 코드가 동일해야하므로 모든 하위 클래스가 Equals 메서드에서 공용 속성 만 사용합니까? 그렇지 않은 경우 공용 속성뿐만 아니라 모든 속성을 반복 할 수 있습니다.

추가 편집 : 또한 해시가 Int.MaxValue보다 커지면 예외를 방지하기 위해 속성 루프 주위에 unchecked을 추가하는 것이 좋습니다.

+0

+1 특히 "해시 코드와 일치하는"발언. 객체 자체에 변경 사항이 없으면 결과를 캐싱 할 수 있으므로 리플렉션 자체로 인해 GetHashCode가 느려지지는 않습니다. 문제는 호출간에 개체가 변경되지 않는다는 것이 중요하지 않다는 것입니다. –

+0

성능에 대한 징벌과 '확인되지 않음'에 대한 메모에 감사드립니다. 필자의 경우 성능에 눈에 띄게 영향을 줄 수있는 충분한 객체 (아마도 수천 개의 인스턴스)를 다루지 않을 것입니다. 그래도 나는 돌아가서 제가 향하고있는 방향을 재고 할 것입니다. – JMD

0

반사를 사용하는 것이 다소 느리지 만 어떤 경우에는 허용됩니다. GetHashCode 함수는 클래스의 인스턴스가 해시 테이블이나 사전의 키일 때 사용됩니다. 대부분의 경우 필요할 때 알 수 있습니다. 수동으로 작성하는 대신 GetHashCode 및 Equals 함수를 생성 할 수있는 Resharper (example)과 같은 도구가 있습니다.

+0

"대부분의 경우 필요할 때 알 수 있습니다." 하아! 그것이 내가 생각했던 거죠! 이제는 DevExpress XtraGrid (격자 모양의 컨트롤)를 사용하여 내 객체의 List <>에 바인딩하면 DevExpress 코드가 내 객체를 키로 사용하여 Hashtable을 생성하는 경우가 있습니다. 그런 다음 충돌합니다. 바하마! – RenniePet

1

기본 규칙을 놓쳤습니다. GetHashCode() 결과는 개체의 전체 수명 동안 동일하게 유지되어야합니다. GetHashCode 구현에서는 반복되는 속성을 변경할 수 있으므로 보장 할 수 없습니다.

+2

-1 - 이것은 사실이 아닙니다. http://msdn.microsoft.com/en-us/library/system.object.gethashcode를 확인하십시오.aspx 명시 적으로 "개체 상태에 대한 수정이없는 한 동일한 해시 코드를 일관되게 반환해야 함 *" –

+1

Eric Lippert는 다음과 같이 썼습니다. "규칙 : GetHashCode에 의해 반환 된 정수는 개체가 데이터에 포함되어 있으면 절대로 변경해서는 안됩니다. 구조 안정적인 해시 코드에 따라 달라집니다 ". 그는 또한 그 결과가 절대로 바뀌지 않을 것이라고 지침서에 썼다. 그의 전체 설명을 보려면 원래 게시물을 읽어보십시오. http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx –

+0

해시가 객체의 상태에서 파생되는 경우 GetHashCode()가 객체의 전체 수명 동안 동일하게 유지되는 결과입니다. 이 규칙은 객체의 상태를 사용하여 해시 코드를 생성하는 모든 예를 무효화합니다. 규칙에 의해, 해시 코드의 파생에 들어가는 값의 변경은, 구축이 시작된 순간부터 변경할 수 없습니다. – JMD