今天,想使用自定义的类型作为Dictionary<TKey, TValue> 的键类型,不可避免的要使用到这个接口。如果另外定义一个实现类,使用者必须首先知道有这个类存在,这样调用方才会得到正确的结果。自然想到的办法就是这个自定义类型主动实现IEqualityComparer<T>接口,但是Dictionary<TKey, TValue> 类型并不会去检查这个键对象有没有实现IEqualityComparer<T>接口。
如果构造Dictionary<TKey, TValue> 泛型集合的实例对象时候,没有提供一个实现了IEqualityComparer<T>接口的实例对象,Dictionary<TKey, TValue>默认使用EqualityComparer<T> 泛型类的 Default属性。看看IEqualityComparer<T>接口MSDN的说明:使用此接口,可以实现集合的自定义相等比较。也就是说,对于类型 T,您可以创建自己的相等定义,并指定该定义可与接受 IEqualityComparer<T>泛型接口的集合类型一起使用。在 .NET Framework 中,Dictionary<TKey, TValue> 泛型集合类型的构造函数接受此接口。继续看EqualityComparer<T> 泛型类Default属性的MSDN的说明:Default 属性检查类型 T 是否实现此 System.IEquatable<T> 泛型接口,如果实现,该属性将返回一个使用该实现的 EqualityComparer<T>。否则,它返回一个使用 T 提供的 Object.Equals 和 Object.GetHashCode 的重写的 EqualityComparer<T>。
看到上面的说明,我天真的以为实现了System.IEquatable<T> 泛型接口就可以在Dictionary<TKey, TValue> 泛型集合的键中使用自己定义的类了。结果发现无论如何都不能使程序按照设想中的运行。最后发现MSDN中关于System.IEquatable<T>的实现者说明:如果实现 IEquatable<T>,还应重写 Object.Equals(Object) 和 GetHashCode 的基类实现,以便其行为与 IEquatable<T>.Equals 方法的行为一致。尝试着重写了这两个方法,一切都OK了。后来查看了.Net Framework源代码才明白了,实际上,对于EqualityComparer<T> 泛型类来说前面这个重写是必须的,因为前面说的“Default 属性检查类型 T 是否实现此 System.IEquatable<T> 泛型接口,如果实现,该属性将返回一个使用该实现的 EqualityComparer<T>”,实际上这个未公开的 System.IEquatable<T>实现内部其实使用的还是Object.Equals(Object)方法来做比较。
这就比较郁闷了,对于Dictionary<TKey, TValue>来说,实现System.IEquatable<T>其实没什么用,始终还是要重写 Object.Equals(Object) 和 GetHashCode。
有关的文章可以看这两篇:
1、http://www.joycode.com/vbcti/archive/2009/02/20/115473.joy
2、http://www.cnblogs.com/ldp615/archive/2009/09/05/1560791.html