Log Stash

as an Industrial Personnel

Note

TIL: C#에서 enum이나 struct를 Dictionary의 Key값으로 사용하면 쓰레기가 생긴다

SavvyTuna 2017. 7. 6. 22:21

C#에서 enum값은 레퍼런스 타입이 아니다. 때문에 평소에 이리저리 값을 넘기고 받을 때 동적할당, 박싱/언박싱에대한 죄책감을 느끼지 않으며 쓰고 있었다. 하지만 알고보니 enum이 Dictionary의 키값으로 쓰이게 되면, Dictionary 내부에서 키값들이 같은지 비교할 때 enum을 박싱하면서 쓰레기가 생기게 된다.

예를 들면 이렇게

enum SomeType 
{
    None,
    Gold,
    Point,
    Cash,
}

Dictionary<SomeType, String> type2Asdf = new Dictionary<SomeType, String>();

별 생각없이 Key자리에 enum을 넣어 왔었는데. 이렇게 하면 Dictionary내부에 쓰레기가 생긴다.

Dictionary에서는 키값이 같은지 여부를 판별할때 IEqualityComarer라는 인터페이스를 사용한다. 따로 Dictionary에 비교자 객체를 집어넣지 않는 한, 이 비교자 객체의 기본값은 EqualityComparer<T>.Default가 된다. 링크로 걸려있는 MSDN 문서에 의하면, 저 Default 프로퍼티는 T타입이 System.IEquatable<T>을 따로 구현하지 않았을 경우에 EqualityComparer<T>를 반환하는데, 얘는 Object.EqualsObject.GetHashCode을 기본 비교 함수들로 사용한다고 한다.

다른 primitive 타입들은 IEquatable을 구현해놓은 반면에 enum은 구현해 놓지 않아서 비교하는데 Obejct.Equals를 쓰게되고, 여기에서 enum을 Object로 박싱하게되니 쓰레기가 생기게 된다. struct도 같은 이유.

해결책은 간단하게 저 비교자 인터페이스를 하나 구현해서 Dictionary에게 넘겨주면 된다.

// 비교자 함수 객체
public struct SomeTypeComparer : IEqualityComparer<SomeType>
{
    public bool Equals(SomeType a, SomeType b) { return a == b; }
    public int GetHashCode(SomeType a) { return (int)a; }
}

// 생성자로 넘겨주자
Dictionary<SomeType, String> type2Asdf = new Dictionary<SomeType, String>(new SomeTypeComparer());

아니면 그냥 그냥 int를 써버리던가..

References