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