Should I implement non-generic GetHashCode
and Equals
if my class implements IEqualityComparer<T>
?
Update: My hope was that MS updated implementation of their collection when they introduced IEqualityComparer<T>
. So I thought that Dictionary
and any other collection classes will check internally if my class implements IEqualityComparer<T>
and use not generic methods GetHashCode
and Equals
only if that interface is not implemented. Without collections support that interface has very little value.
Update2: I just checked Dictionary.FindEntry(TKey key)
using ILSpy. It uses IEqualityComparer<TKey>
(varriable comparer
below). In fact I did not find any using of not generic GetHashCode
and Equals
functions at all.
int num = this.comparer.GetHashCode(key) & 2147483647;
for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.entries[i].next)
{
if (this.entries[i].hashCode == num
&& this.comparer.Equals(this.entries[i].key, key))
{
return i;
}
}
So it seems to that my class only needs to implement IEqualityComparer<T>
to be properly used with Dictionary
.
I understand that there will be no harm to implement not generic functions just in case.
But should we spend time if it brings no value?
I will make my question more specific:
Should I implement non-generic GetHashCode
and Equals
if my class implements IEqualityComparer<T>
and:
GetHashCode
and Equals
methods of my code. Does Microsoft code still needs non generic versions to work properly?
Update3 : I think I got it. I thought that IEqualityComparer<T>
is to be implemented inside my class. In that case we would have generic and not generic versions of methods in one place. That is not how IEqualityComparer<T>
should be used. It should be implemented as separate class and used as parameter.
Thanks to everybody.
It depends. IEqualityComparer<T>
is used to compare two instances of a type T
- and typically implemented by a separate comparer class. Normally you wouldn't not implement this in the class type T
. It's meant to provide an alternative comparison for use with types that support his.
If you're implementing this within the class itself, you'd typically implement IEquatable<T>
.
That being said, it's often useful to override Object.Equals
, which is typically very simple as you can use the IEquatable<T>.Equals
method to implement Object.Equals
. This makes it "inexpensive" to implement. As Object.Equals
may be used, it will provide a consistent meaning to equality, so it's generally a good idea to implement.
If your object is going to be used as a key in a hash, such as a Dictionary<T,U>
or a HashSet<T>
, then you should override GetHashCode
. If there's even a chance that it may be used in this manner, overriding this method is beneficial. Typically, I find that it's useful to override GetHashCode
any time I implement equality, just in case I will use the type as a key later.
IEqualityComparer is meant to replace the default implemenation of GetHashCode and Equals every .NET object already has. This interface is only used by Dictionaries and (Hash)Sets to use a different hashing and comparison scheme as the object by default uses.
If your object is used in Dictionaries and HashTables as key you should first to override Equals and GetHashCode to let the Sets/Dictionaries use the default comparer (the one you call EqualityComparere.Default) for your object which does call Equals and GetHashCode of your object anyway.
The only reason to provide an external comparer via IEqualityComparer is to use a different comparison scheme. Eg for strings you can choose from the BCL StringComparer class between case sensitive and case insensitive variants.
Update1
The intention of this question was why List and other collections always use the default comparer and not the one provided by the object. If an object does implement Equals and GetHashCode already why should List not use them if the object does at the same time also implements IEqualityComparer? Since List does not provide a ctor which does allow to use a different comparer it does need to use the default one.
But if you want to use different ones you always can use LINQ which does fix this issue by allowing you to pass explicitely your own comparer for a specific metho. Eg Enumerable.Contains has an overload where you can pass in your own comparer.
From MSDN Sample:
Product[] fruits = { new Product { Name = "apple", Code = 9 },
new Product { Name = "orange", Code = 4 },
new Product { Name = "lemon", Code = 12 } };
Product apple = new Product { Name = "apple", Code = 9 };
Product kiwi = new Product {Name = "kiwi", Code = 8 };
ProductComparer prodc = new ProductComparer();
bool hasApple = fruits.Contains(apple, prodc);
bool hasKiwi = fruits.Contains(kiwi, prodc);
If I understand you correctly and you're asking if you also have to implement IEqualityComparer
if you implement IEqualityComparer<T>
, then the answer is you don't have to, but it's probably a good idea. It will just make your comparer more compatible with existing code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.