Search code examples
c#abstractgethashcode

Can I implement a base GetHashCode() that will work for all extensions of my abstract base class?


I got reading this question here which led me to this article here.

I've got an abstract base class that allows me to constrain methods to accept only my classes that extend my abstract base class (basic polymorphism). My question is: Can I implement GetHashCode() in my abstract base class to provide a suitable override for any concrete implementation? (I.e. to avoid overriding GetHashCode() in each concrete class.)

I'm imagining a method in my abstract base class something like this:

public abstract class FooBase
{
    private static readonly int prime_seed = 13;
    private static readonly int prime_factor = 7;

    public override int GetHashCode()
    {
        // Seed using the hashcode for this concrete class' Type so
        // two classes with the same properties return different hashes.
        int hash = prime_seed * this.GetType().GetHashCode();
        // Get this concrete class' public properties.
        var props = this.GetType().GetProperties(BindingFlags.Public);
        foreach (var prop in props)
        {
            // Factor in each of this concrete class' public properties' hashcodes.
            hash = (hash * prime_factor) + prop.GetHashCode();
        }
        return hash;
    }
}

This seems to work in some basic equality unit tests but I feel like I've overlooked something. I still have to provide an override in each concrete class to avoid the compiler Warning about not overriding GetHashCode(), but at least this way I don't have to manually write an implementation for each one.


Solution

  • Does this perform better than:

    public override int GetHashCode()
    {
        return 1;
    }
    

    A key to a Hash function is it must be fast to compute. With reflection, you might lose all the benefits you stand to gain from having a hash.

    It would be worth it to benchmark.

    Also, hash codes must be equal when Equals returns true, so will all subclasses use only public properties in their Equals method? If not, you might consider looping over all properties, not just public ones.

    Edit to add: Also, consider adding unchecked around your property loop to prevent an exception if the hash gets bigger than Int.MaxValue.