HashSet<T>은 C#에서 Set 대용으로(ie, 중복을 허용하지 않는 컬렉션) 흔히 쓰는데, equality를 hash code를 이용해서 검증하기 때문에 Object.GetHashCode()를 오버라이딩해 주어야 한다.
문제는 어느 인터페이스를 구현할 것인가이다. 구글에서 대충 검색하다 보면 IEqualityComparer<T>와 IEquatable<T>이 나타날 텐데, 감으로는 IEquatable<T>인 것 같지만(맞음) 과연 IEqualityComparer<T>는 무엇인가 하는 궁금증이 생긴다.
(사실 이 이유만은 아니다. Visual Studio에서 IEquatable의 정의를 따라가 보면,
bool Equals(T other)
만 있고 GetHashCode가 없어서 IEquatable<T> 구현 없이
그냥 Equals와 GetHashCode 를 override하고 말겠다는 생각이 든다...*)
어찌됐든, 두 인터페이스 중 어느 것을 써야 하는가에 대해서는, 아래 문서가 이를 잘 설명하고 있는데, 특히 마지막 답변이 이해하기 쉬운 예제와 함께 잘 설명하고 있다.
http://stackoverflow.com/questions/9316918/what-is-the-difference-between-iequalitycomparert-and-iequatablet
1. class T : IEquatable<T> 형태로 쓴다.
* class MyClass : IEquatable<T> 형태는 (대개) 의미가 없다.
* public bool Equals(T other)를 구현하면 된다.
- Object.Equals(Object o)에 비해서 parameter가 T가 되고(캐스팅이나 as가 필요 없어짐#),
override 키워드를 안 써도 경고문이 뜨지 않는 장점이 있다. <주>
* ==, !=, GetHashCode와 nongeneric Equals도 오버라이딩해야 한다.
- ...라고는 하는데 GetHashCode()만 해도 HashSet을 쓰는 데는 별 문제가 없다(아직까지는...).
2. IEqualityComparer는 특수한 상황에서만 쓰이는 동일성 비교 policy를 만들 때 쓴다. 예를 들어 특정 '조건을 만족하면 같은 것으로 치는' 상황이다. HashSet을 예로 들면, 평소에는 유일성이 인정되는 객체는 무조건 다 받아주다가(Add), 어떤 상황이 되면, 특정 조건을 만족하는 객체는 무조건 받지 않는 것이다.
class Person {
public int Age;
} // Equals를 재정의하지 않았으므로 ReferenceEquals가 호출될 것이다.
class AgeEqualityTester : IEqualityComparer<Person> {
public bool Equals(Person x, Person y) { return (x.Age==y.Age); }
public int GetHashCode(Person p) { return p.Age; }
}
var people = new Person[] {new Person {age=23} };
var person = new Person() { age=23 };
var b1 = people.Contains(person); //FALSE;
var b2 = people.Contains(person, new AgeEqualityTester()); //TRUE
여기서 ICollection.Contains() 메서드의 새로운 사용법을 배울 수 있다 :)
Person/People 예는 이해하기는 쉬운데 별로 재미는 없다. 이런 걸 생각해 보자:
복잡한 weighted graph data structure가 있다. 이것의 개략적인 모양을 2차원 화면에 그리려 하는데, 모든 edge를 나타내기는 어려워서, weight만 다르고 시작점과 끝점이 같은 edge가 여러 개 있을 때 그들 중 하나만 그리기로 하였다. --> 한 번 그린 edge를 set에 넣고 두 번째부터 안 그리든지, 그릴 set을 처음에 만들고 시작하든지 알아서...
그럼에도 모르겠는 거: IEquatable에 왜 GetHashCode()가 포함되어 있지 않은가?
*또한 IEquatable에 없는 GetHashCode 멤버 함수가 IEqualityComparer에는 있다! -_-
그런데 IEqualityComparer를 구현해서 HashSet에서의 동일성 검증에 사용하려 하면, 그렇게 되지도 않는다. 우선 Equals의 원형부터
public bool Equals(object objA, object objB)
로서, 마치 static 함수 같은 모양을 하고 있다(그러나 static은 아니다). C++/STL에서 operator overloading 하던 때의 짜증이 떠오른다... 이는 equality comparer라는 이름이 이미 암시하고 있기는 하다. 비교 대상이 아니라 '두 대상을 비교해 주는 무언가'라는 것.
# as는 이렇게 쓴다. 캐스트와 비슷하나, 변환이 실패했을 때 exception을 발생시키지 않고 그냥 null을 리턴한다.
class MyType {int m1; int m2;} // 모두 public 가정
public bool Equals(Object obj) {
var p = obj as MyType; // 캐스트와 비슷
if(p==null) return false;
return m1==p.m1 && m2==p.m2; // custom equality test 예제
}
Wednesday, May 22, 2013
Subscribe to:
Post Comments (Atom)
"Gossip Girl" star Michelle Trachtenberg dies at 39
미셸 트랙튼버그 하우스에서 심장 이식 받았던 환자로 나왔는데 현실에서는 간이식을 받았었구나 가십걸이나 버피더뱀파이어슬레이어 이제 정주행해 볼까... 블로그도 다시 살려 볼까 훠훠

-
텍스트박스에서 엔터를 치면 자동으로 입력되게 하려고 keyup 이벤트 핸들러를 등록했다. 잘 동작하는 듯했는데 alert창을 닫아도 닫아도 계속 열리는 것이다. 크롬이어서 다행이지 IE였으면 무한히 열렸을 거야...스페이스바로 눌러보길 잘했...
-
MathJax è Word MS Word 2007부터는 MathML을 문서에 바로 붙여넣을 수 있다. 이 블로그의 거의 대부분의 수식은 MathJax로 작성되어 있는데, 오른쪽 버튼 클릭하고 메뉴에서 MathML 또는 TeX 형식으로 ex...
-
진짜 되는 건 아니고 흉내낼 수는 있다. 새 창을 누르면 아무 것도 안 변한 것 같지만 PowerPoint 창 제목이 바뀌어 있다: 프레젠테이션1:2에서 :2 부분이 같은 파일을 연 창 여러 개 중 2번째라는 뜻이다('프레...
No comments:
Post a Comment