简体   繁体   中英

Should I implement non-generic GetHashCode and Equals if my class implements IEqualityComparer<T>?

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:

  1. I do not use not generic collections in my code
  2. Third party code does not call 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM