简体   繁体   中英

When implementing IEqualityComparer<T>.GetHashCode(T obj), can I use the current instance's state, or do I have to use obj?

How come when I implement IEqualityComparer, it has a parameter for GetHashCode(T obj)? It's not a static object of course, so why can't I just use the current instance's state to generate the hash code? Is this == obj ?

I'm curious because I'm trying to do this:

public abstract class BaseClass : IEqualityComparer<BaseClass>
{
    public abstract int GetHashCode(BaseClass obj);
}

public class DerivedClass : BaseClass
{
    public int MyData;

    public override int GetHashCode(BaseClass obj)
    {
        return MyData.GetHashCode();
        // Or do I have to do this:
        // return (DerivedClass)obj.MyData.GetHashCode();
    }
}

I'm trying to prevent doing the cast, since it's being used in really high-performance code.

I think the main issue here is that you're confusing IEqualityComparer<T> with IEquatable<T> .

IEquatable<T> defines a method for determining if the current instance ( this ) is equal to an instance of the same type. In other words it's used for testing objA.Equals(objB) . When implementing this interface, it is recommended that you also override the GetHashCode() instance method.

IEqualityComparer<T> defines methods for testing whether two objects of the given type are equal, in other words, it's for testing comparer.Equals(objA, objB) . Hence the necessity to to provide an object as a parameter to GetHashCode (which, remember is different than the GetHashCode that it inherits from object )

You can think of IEquatable<T> as your object's way of saying, " this is how I know if I am equal to something else, " and IEqualityComparer<T> as your object's way of saying, " this is how I know if two other things are equal ".

For some good examples of how these two interfaces are used in the framework see:

  • String which implements IEquatable<string>
  • StringComparer which implements IEqualityComparer<string>

Should you use the current state of an IEqualityComparer<T> to determine the hash code? If the state is at all mutable, then no! Anywhere where the hash is used (eg HashSet<T> or Dictionary<T, V> ) the hash code will be cached and used for efficient lookup. If that hash code can change because the state of the comparer changes, that would totally destroy the usefulness of the data structure storing the hash. Now, if the state is not mutable (ie it's set only when creating the comparer and cannot be modified throughout the lifetime of the comparer), then yes, you can, but I would still recommend against it, unless you have a really good reason.

Finally, you mentioned performance. Honestly, this sounds like premature optimization . I'd recommend not worrying so much about performance until you can be sure that this particular line of code is causing a problem.

If you are not using information from passed in obj arguments your hash code will not vary for different incoming objects and will not be useful. Comparer is not instance of object you want to get hash code for or compare to.

Indeed you can use local fields of comaprer in GetHashCode and even can return MyData as hash code as shown in your sample - it will still satisfy GetHashCode requirement to "return the same value data for the same object". But in your sample all hash codes will be the same for instance of comparer and hence using it for Dictionary will essentially turn dictionary into list.

The same applies to Equals call - indeed you can return true all the time, but how useful it will be?

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