문제

나는 언제, 어떻게 재정의하는지에 대한 10 가지 질문을 읽었습니다. GetHashCode 그러나 여전히 내가 얻지 못하는 것이 있습니다. 대부분의 구현 GetHashCode 객체 필드의 해시 코드를 기반으로하지만 값이 인용되었습니다. GetHashCode 물체의 수명에 따라 절대 변하지 않아야합니다. 기반의 필드가 변이 가능하다면 어떻게 작동합니까? 또한 사전 조회 등을 원한다면 참조 평등을 기반으로하기를 원한다면 어떻게해야합니까? Equals?

나는 주로 무시하고있다 Equals 단위 테스트를 쉽게 테스트하기 위해 직렬화 코드를 테스트하기 위해 직렬화 및 사제화 (내 경우 XML)가 참조 평등을 죽이므로 적어도 가치 평등에 의해 정확한지 확인하고 싶습니다. 이 나쁜 관행을 무시하는 것입니다 Equals 이 경우? 기본적으로 대부분의 실행 코드에서 나는 참조 평등을 원하고 항상 사용합니다. == 그리고 나는 그것을 무시하지 않습니다. 새 메소드 만 만들어야합니다 ValueEquals 또는 재정의하는 대신 무언가 Equals? 나는 프레임 워크가 항상 사용한다고 가정했다 == 그리고 아닙니다 Equals 사물을 비교하기 위해 Equals 당신이 평등에 대한 두 번째 정의를 원한다면 그 목적처럼 보였기 때문에 == 운영자. 다른 몇 가지 질문을 읽음으로써 그렇지 않은 것 같습니다.

편집하다:

내 의도는 불분명 한 것 같다. 내 말은, 나는 평범한 기준 평등, 기본 행동, 놀라움이없는 시간의 99%가 시간을 원한다는 것입니다. 매우 드문 경우의 경우 가치 평등을 원하고 사용하여 가치 평등을 명시 적으로 요청하고 싶습니다. .Equals 대신에 ==.

이 작업을 수행하면 컴파일러가 재정의하는 것이 좋습니다 GetHashCode 또한이 질문이 나온 방식입니다. 모순되는 목표가있는 것처럼 보였습니다 GetHashCode 변이 가능한 물체에 적용될 때 다음과 같습니다.

  1. 만약에 a.Equals(b) 그 다음에 a.GetHashCode() ~해야 한다 == b.GetHashCode().
  2. 의 가치 a.GetHashCode() 평생 동안 변하지 않아야합니다 a.

객체의 상태가 변하면 우리는 .Equals() 변화하는 것은 그 의미입니다 GetHashCode 변경 사항에 맞게 변경해야합니다 .Equals(), 하지만 GetHashCode 변경해서는 안됩니다.

왜이 모순이있는 것 같습니까? 이러한 권장 사항은 변한 물체에 적용되지 않습니까? 아마도 가정했지만, 내가 구조가 아닌 클래스를 언급하고 있다고 언급 할 가치가있을 수 있습니다.

해결:

나는 Jaredpar를 받아 들인 것으로 표시하지만 주로 주석 상호 작용에 대해서는 표시합니다. 내가 이것에서 배운 것을 요약하는 것은 모든 목표를 달성하고 가장자리에서 기발한 행동을 피하는 유일한 방법은 Equals 그리고 GetHashCode 불변의 필드를 기반으로하거나 구현 IEquatable. 이런 종류는 우선의 유용성을 감소시키는 것 같습니다. Equals 참조 유형의 경우, 대부분의 참조 유형은 일반적으로 기본 키로 식별하기 위해 관계형 데이터베이스에 저장되지 않는 한 일반적으로 불변의 필드가 없습니다.

도움이 되었습니까?

해결책

기반의 필드가 변이 가능하다면 어떻게 작동합니까?

객체가 변경됨에 따라 해시 코드가 변경되는 것은 아닙니다. 그것은 당신이 읽은 기사에 나열된 모든 이유에 대한 문제입니다. 불행히도 이것은 일반적으로 코너 케이스에서만 나타나는 문제의 유형입니다. 따라서 개발자들은 나쁜 행동을 피하는 경향이 있습니다.

또한 사전 조회 등을 원한다면 내 재정의 평등이 아닌 참조 평등을 기반으로하기를 원한다면 어떻게해야합니까?

인터페이스와 같은 인터페이스를 구현하는 한 IEquatable<T> 이것은 문제가되지 않아야합니다. 대부분의 사전 구현은 사용할 방식으로 평등 비교를 선택합니다. IEquatable<T> 대상 위에. 심지어 ~ ~없이 IEquatable<T>, 대부분의 기본값은 object.equals ()를 호출하여 구현에 들어갑니다.

기본적으로 대부분의 실행 코드에서 나는 참조 평등을 원하며 항상 ==를 사용하고 그것을 무시하지 않습니다.

객체가 가치 평등으로 행동 할 것으로 기대하는 경우 모든 비교에 대한 가치 평등을 시행하려면 == 및! =를 재정의해야합니다. 사용자는 여전히 참조 평등을 원하는 경우에도 객체를 사용할 수 있습니다.

나는 프레임 워크가 항상 ==를 사용하지만 사물을 비교하기 위해 동일하지 않다고 가정했다.

BCL이 사용하는 것은 시간이 지남에 따라 약간 변경되었습니다. 이제 평등을 사용하는 대부분의 경우가 필요합니다 IEqualityComparer<T> 인스턴스 및 평등을 위해 사용하십시오. 지정되지 않은 경우 사용합니다. EqualityComparer<T>.Default 하나를 찾으려면. 최악의 경우 이것은 대상을 호출하는 데 기본값이됩니다

다른 팁

변한 객체가있는 경우 실제로 사용할 수 없으므로 gethashcode 메소드를 재정의하는 데 많은 점이 없습니다. 예를 들어 Dictionary 그리고 HashSet 각 품목을 양동이에 배치하는 컬렉션. 컬렉션의 키로 사용되는 동안 객체를 변경하면 해시 코드가 더 이상 객체가있는 버킷과 일치하지 않으므로 컬렉션이 제대로 작동하지 않으며 객체를 다시 찾지 못할 수도 있습니다.

조회를 원한다면 사용하지 않으려면 GetHashCode 또는 Equals 수업 방법, 항상 자신의 IEqualityComparer 당신이 만들 때 대신 사용할 구현 Dictionary.

그만큼 Equals 방법은 가치 평등을위한 것이므로 그런 식으로 구현하는 것은 잘못이 아닙니다.

와우, 그것은 실제로 하나의 몇 가지 질문입니다 :-). 그래서 하나는 다른 사람을 따르는 것 :

gethashcode의 값은 물체의 수명에 걸쳐 절대로 변하지 않아야한다고 인용되었습니다. 기반의 필드가 변이 가능하다면 어떻게 작동합니까?

이 일반적인 조언은 해시 가능/사전 등의 객체를 키로 사용하려는 경우를위한 것입니다. 해시블은 일반적으로 해시가 변경되지 않아야합니다. 키를 저장하고 검색하는 방법을 결정하기 때문에 해시가 변경되지 않아야합니다. 해시가 변경되면 해시 가능이 더 이상 객체를 찾지 못할 것입니다.

Java의 문서를 인용합니다 지도 상호 작용:

참고 : Mutable Object가 맵 키로 사용되면주의를 기울여야합니다. 객체의 값이 비교에 영향을 미치는 방식으로 객체의 값이 변경되는 반면 객체는 맵의 핵심 인 경우 맵의 동작이 지정되지 않습니다.

일반적으로 사용하는 것은 나쁜 생각입니다 어느 해시 테이블의 키로 변한 변이 가능한 물체 : 해시 테이블에 추가 된 후 키가 변경되면 어떻게 해야하는지 명확하지 않습니다. 해시 테이블이 저장된 키를 통해 또는 새 키를 통해 또는 둘 다를 통해 저장된 객체를 반환해야합니까?

따라서 진정한 조언은 다음과 같습니다. 불변의 물체 만 키로 사용하고 해시 코드가 변경되지 않도록하십시오 (대체가 불변이없는 경우 자동으로).

또한 사전 조회 등을 원한다면 내 재정의 평등이 아닌 참조 평등을 기반으로하기를 원한다면 어떻게해야합니까?

글쎄, 그런 작동하는 사전 구현을 찾으십시오. 그러나 표준 라이브러리 사전은 해시 코드와 동등한 것을 사용하며이를 변경할 방법이 없습니다.

나는 주로 직렬화 코드를 테스트하는 것이 쉽게 우선하고 있습니다. 직렬화 코드 (내 경우 XML에)가 참조 평등을 죽인다고 가정하면 적어도 가치 평등에 의해 정확한지 확인하고 싶습니다. 이 경우에 동등한 것을 무시하는이 나쁜 관행입니까?

아니, 나는 그것을 완벽하게 받아 들일 수 있음을 알았습니다. 그러나 이러한 객체를 사전/해시 테이블의 키와 같은 객체를 변경할 수 있으므로 사용해서는 안됩니다. 위 참조.

여기서 근본적인 주제는 객체를 가장 잘 식별하는 방법입니다. 해당 과정에서 참조 무결성이 손실되기 때문에 중요한 직렬화/사제화를 언급합니다.

짧은 대답은, 객체는 그렇게 할 수있는 가장 작은 불변의 필드 세트로 고유하게 식별해야한다는 것입니다. 이것들은 gethashcode를 재정의 할 때 사용해야하는 필드이며 동등합니다.

테스트하기 위해 필요한 어설 션을 정의하는 것이 완벽하게 합리적입니다. 일반적으로 유형 자체에 정의되지 않고 테스트 스위트의 유틸리티 방법으로 정의됩니다. 아마도 testsuite.assertequals (myclass, myclass)일까요?

gethashcode와 동일은 함께 작동해야합니다. gethashcode는 동일하면 두 객체에 대해 동일한 값을 반환해야합니다. 두 객체에 동일한 해시 코드가있는 경우에만 평등은 true를 반환해야합니다. (두 객체가 동일하지는 않지만 동일한 해시 코드를 반환 할 수 있습니다). 이 주제를 정면으로 해결하는 웹 페이지가 많이 있습니다.

나는 C#에 대해 잘 모르겠지만, 상대적인 멍청이라는 것을 알지 못하지만 Java에서는 equals ()를 무시하면 hashcode ()를 무시해야합니다. 또한 동일한 캐치 22가 있습니다. 기본적으로 불변의 필드를 사용하는 것을 강요합니다 ... 그러나 이것은 해시 키로 사용되는 클래스에만 문제가되며 Java는 모든 해시 기반 컬렉션에 대한 대체 구현을 가지고 있습니다. 돌연변이 가능한 객체를 열쇠로 사용할 수 있습니다 ... 단지 (보통) "가난한 디자인"으로 눈살을 찌푸립니다.

그리고 나는이 근본적인 문제가 시대를 초월하다는 것을 지적하려는 충동을 느낍니다. 아담이 젊은이 였기 때문에 주변에있었습니다.

나는 나보다 나이가 많은 Fortran 코드에서 작업했는데 (나는 36 세), 사용자 이름이 바뀌면 (소녀가 결혼하거나 이혼했을 때와 같은 ;-) ... 따라서 채택 된 솔루션은 엔지니어링이었다. : gethashcode "method"는 이전에 계산 된 해시 코드를 기억하고, 해시 코드를 다시 계산하고 (즉, 가상 iSdirty 마커) 및 키 필드가 변경되면 NULL을 반환합니다. 이로 인해 캐시가 "더러운"사용자 (다른 getPreviousHashCode를 호출함으로써)를 삭제 한 다음 캐시가 NULL을 반환하여 사용자가 데이터베이스에서 다시 읽게됩니다. 흥미롭고 가치있는 해킹; 내가 스스로 그렇게 말하더라도 ;-)

O (1) 액세스 (모든 경우에 바람직 함)에 대한 돌연변이 (코너 케이스에서만 바람직 함)를 트레이드 오프 할 것입니다. 엔지니어링에 오신 것을 환영합니다. 정보에 입각 한 타협의 땅.

건배. 키이스.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top