3

In my class, I have implemented Equals and GetHashCode. yet when I use it as key for a dictionary in my C# code, I get the error : "Key not found exception" Thanks,

public class Time: IEquatable<Time>
{
    public String hour;
    public String minute;

    public Time()
    {
        hour = "00";
        minute = "00";
    }

    public Time(String hour, String minute)
        : this()
    {
        this.hour = hour;
        this.minute = minute;
    }

    public override int GetHashCode()
    {
        int hash = int.Parse(hour) * 60 + int.Parse(minute);
        return hash.GetHashCode();
    }
    public override bool Equals(Time time)
    {

            return (this.hour == time.hour && this.minute == time.minute);

    }

}

And The code where I am using it:

Dictionary<Time, int> time2RowIndex = new Dictionary<Time, int>();

...

int beginRow = 0;
if(time2RowIndex.ContainsKey(time.hour))
      beginRow = time2RowIndex [time.hour];
Saeid Farivar
  • 1,667
  • 24
  • 43

1 Answers1

5

Try this. The trick is to override Equals from object (and GetHashCode) instead of just implementing IEquatable<>.

Also, if Hour or Minute on the Time object change after the instance of Time has been added to the dictionary, the bucket (selected by hash code at the time of the add) will no longer match the hash code on the object. This means that even if you present an object of equal value to the dictionary (say with ContainsKey), it won't find the original item in the dictionary (because the hash bucket it will look in doesn't contain the original object). It's a best practice that all fields referenced in the GetHashCode function be readonly to avoid these situations.

public class Time : IEquatable<Time>
{
    public String Hour;
    public String Minute;

    public Time()
    {
        Hour = "00";
        Minute = "00";
    }

    public Time(String hour, String minute)
        : this()
    {
        this.Hour = hour;
        this.Minute = minute;
    }

    public override int GetHashCode()
    {
        return int.Parse(Hour) * 60 + int.Parse(Minute);
    }

    public override bool Equals(object obj)
    {
        var time = obj as Time;
        return !ReferenceEquals(time, null) && Equals(time);
    }

    public bool Equals(Time time)
    {
        return string.Equals(Hour, time.Hour, StringComparison.Ordinal) && string.Equals(Minute, time.Minute, StringComparison.Ordinal);
    }
}
mlorbetske
  • 5,529
  • 2
  • 28
  • 40
  • 1
    Thanks @mlorbetske it worked, but can you explain what was the error? I guess the error was because I wasn't implementing Equals(object obj) ? right? – Saeid Farivar Dec 29 '12 at 07:26
  • 1
    Yep, as far as I know `object.Equals` is used for the equality check that's done after using the hash code to find the candidate keys in the dictionary; since it wasn't implemented, the `IEquatable.Equals` method wasn't being called to assert that they are in fact equal. – mlorbetske Dec 29 '12 at 07:28