none
[WP8.1][C#] Overriding GetHashCode() inside IEqualityComparer-based class RRS feed

  • Question

  • Hi,

    I have two List<classname> which I want to compare based on one of the classname properties. The class structure basically looks like this:

    class classname
    {
        string uniqueid;
        string pagename;
        string displaytext;
        bool favorite;
    }

    And only the favorite property can change between the lists. The list items are identical in all other regards and contain no confidential information or anything. I read this article where implementation of the IEqualityComparer is discussed.

    So I created a FavComparer : IEqualityComparer<classname> class to compare both lists based on the favorite property using SequenceEqual():

    sourcelist.SequenceEqual(sourcelist_backup, new FavComparer());

    However, I am not very familiar with using hash codes. I read into it and it seems very confusing. So basically you're supposed to override the GetHashCode() where you perform some seemingly random calculation with prime numbers and the data itself? In my example, wouldn't it suffice to override the GetHashCode method like this...

    public int GetHashCode(classname obj)
    {
        bool hCode = obj.favorite;
        return hCode.GetHashCode();
    }

    ...seeing as the comparer only checks if x.favorite == y.favorite (after checking for nulls etc.), and true and false have different hash codes from what I can see. Or should I still use some calculation with a prime number? Or is there an even better way?

    • Moved by Fred BaoModerator Monday, November 2, 2015 5:26 AM related to .net framework
    Friday, October 30, 2015 4:22 PM

Answers

  • it is ok to just use the favorite property although it feels weird and might be surprising for the maintainer of your code

    but you can probably make it clearer by implementing IEquatable :


    public class classname : IEquatable<classname>
    {
        public override bool Equals(object obj)
        {
            return Equals(obj as other);
        }
    
        public override bool Equals(classname obj)
        {
            var other = obj as classname;
            return other != null && favorite == other.favorite;
        }
        
        public override int GetHashCode()
        {
            return favorite.GetHashCode();
        }
    }

    and then just use: list1.SequenceEqual(list2)

    • Marked as answer by Aria2014 Monday, November 2, 2015 2:39 PM
    Monday, November 2, 2015 12:29 PM

All replies

  • GetHashCode should return values uniformly distributed in the int range.

    The important assumption is that 2 objects that are equal (in the object.Equal or IEquality<>.Equal sense ) must return same hash codes.

    You can read more here:

    https://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.100%29.aspx

    For your class, try something like this:

    public override int GetHashCode()
    {
        unchecked
        {
            var hash = 17;
            hash = hash * 23 + (uniqueid != null ? uniqueid.GetHashCode() : 0);
            hash = hash * 23 + (pagename != null ? pagename.GetHashCode() : 0);
            hash = hash * 23 + (displaytext != null ? displaytext.GetHashCode() : 0);
            hash = hash * 23 + favorite.GetHashCode();
            return hash;
        }
    }

    Friday, October 30, 2015 8:09 PM
  • Thanks for the info. What still confuses me though is the way that both lists are compared. As far as I understand from this article, using sourcelist.SequenceEqual(sourcelist_backup, new FavComparer()) will compare each pair of items in both lists.

    E.g. if sourcelist[0].favorite and sourcelist_backup[0].favorite are both the same, then the GetHashCode() will be the same (either 0 or 1). If the favorite values do not match, then GetHashCode() will return 0 for one and 1 for the other item in the pair and the SequenceEqual operation will return False. So returning just the favorite.GetHashCode() should suffice from what I can tell(?) Would it still be recommended to use a more complicated algorithm to generate hash codes, like the one you posted?

    Saturday, October 31, 2015 8:55 AM
  • To be honest I would look at using Linq, I don't think List == List is an obvious result. What does it mean? Comparers were around before Linq and doesn't offer any where near the flexibility nor transparency.

    http://pauliom.wordpress.com

    Saturday, October 31, 2015 6:20 PM
  • Not sure if I understand you correctly, but SequenceEqual is already a Linq operation:

    https://msdn.microsoft.com/en-us/library/bb342073(v=vs.110).aspx

    The SequenceEqual<tsource>(IEnumerable<tsource>, IEnumerable<tsource>, IEqualityComparer<tsource>) method enumerates the two source sequences in parallel and compares corresponding elements by using the specified IEqualityComparer<t>.</t></tsource></tsource></tsource></tsource>


    • Edited by Aria2014 Sunday, November 1, 2015 10:21 AM
    Sunday, November 1, 2015 10:02 AM
  • Sorry my fault, I didn't read your post properly.

    http://pauliom.wordpress.com

    Sunday, November 1, 2015 10:22 AM
  • it is ok to just use the favorite property although it feels weird and might be surprising for the maintainer of your code

    but you can probably make it clearer by implementing IEquatable :


    public class classname : IEquatable<classname>
    {
        public override bool Equals(object obj)
        {
            return Equals(obj as other);
        }
    
        public override bool Equals(classname obj)
        {
            var other = obj as classname;
            return other != null && favorite == other.favorite;
        }
        
        public override int GetHashCode()
        {
            return favorite.GetHashCode();
        }
    }

    and then just use: list1.SequenceEqual(list2)

    • Marked as answer by Aria2014 Monday, November 2, 2015 2:39 PM
    Monday, November 2, 2015 12:29 PM
  • Roger that. Thanks.
    Monday, November 2, 2015 2:39 PM