0

I am currently trying to use the containskey method to check if a dictionary i have contains a certain key of a custom type. To do this i should override the gethashcode function, which i have, however the containskey method is still not working. There must be something i am not doing right but i havent figured out what exactly in the past 5 hours i have been trying this:

public class Parameter : IEquatable<Parameter>
{
    public string Field { get; set; }
    public string Content { get; set; }

    public bool Equals(Parameter other)
    {
        if (other == null)
        {
            return false;
        }

        return Field.Equals(other.Field) && Content.Equals(other.Content);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + Field.GetHashCode();
            hash = hash * 23 + Content.GetHashCode();
            return hash;
        }
    }
}

public class Trigger : IEquatable<Trigger>
{
    public Dictionary<int, Parameter> Parameters { get; private set; }
    private string Event { get; set; }

    public bool Equals(Trigger item)
    {
        if (item == null)
        {
            return false;
        }

        return Event.Equals(item.Event) && Parameters.Equals(item.Parameters);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            var hash = 17;
            hash = hash * 23 + Parameters.GetHashCode();
            hash = hash * 23 + Event.GetHashCode();
            return hash;
        }
    }
}

For additional clarity: I have a Dictionary(Trigger, State) that i want to check the keys of so i assumed if i made sure all my sub-classes were equatable i could just use the containskey method, but apparently it does not.

Edit: What i have done now is implement Jon Skeet's Dictionary class and use this to do my checks on:

public override bool Equals(object o)
{
    var item = o as Trigger;
    if (item == null)
    {
        return false;
    }

return Event.Equals(item.Event) && Dictionaries.Equals(Parameters, item.Parameters);
}

public override int GetHashCode()
{
    var hash = 17;
    hash = hash * 23 + Dictionaries.GetHashCode(Parameters);
    hash = hash * 23 + Event.GetHashCode();
    return hash;
}
Ken de Jong
  • 219
  • 1
  • 11
  • 1
    I don't see a custom type being used as a key in your code. You're only using int as a key. You need to show the code with the problem. – Stewart Apr 15 '13 at 14:50
  • I have a Dictionary that i am checking this on. The state is another custom class i have but that is not important for this question – Ken de Jong Apr 15 '13 at 14:51

2 Answers2

4

Dictionary<,> doesn't itself override Equals and GetHashCode - so your Trigger implementations are broken. You would need to work out what equality you wanted and implement it yourself.

I have a sample implementation in protobuf-csharp-port which you might want to look at.

EDIT: Your change still isn't quite right. You should implement equality like this:

return Event.Equals(item.Event) && 
       Dictionaries.Equals(Parameters, item.Parameters);

and implement GetHashCode as:

var hash = 17;
hash = hash * 23 + Dictionaries.GetHashCode(Parameters);
hash = hash * 23 + Event.GetHashCode();
return hash;
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I dont get what you mean by this really, i implement my own overrides for gethashcode and equals for my base objects already, so what am i doing wrong? – Ken de Jong Apr 16 '13 at 07:53
  • @KendeJong: Look at your implementations - you're calling `Parameters.Equals` and `Parameters.GetHashCode`, and those *aren't* overridden in Dictionary. – Jon Skeet Apr 16 '13 at 08:16
  • So if i understand correctly, i should implement an override to the "standard" dictionary's equals and gethashcodes? – Ken de Jong Apr 16 '13 at 08:24
  • @KendeJong: No, you should just not call `Equals` and `GetHashCode` on the dictionary - instead, call code to check for equality or compute a hash code in the way I've shown in the linked sample. – Jon Skeet Apr 16 '13 at 08:27
  • Edited question with current solution – Ken de Jong Apr 16 '13 at 08:41
  • @KendeJong: Please don't try to add large amounts of code in comments. Edit your question if appropriate. – Jon Skeet Apr 16 '13 at 08:42
  • Edited some of the comments into the question, a bit new to Stackoverflow and how it handles questions and comments, my apologies :) – Ken de Jong Apr 16 '13 at 08:50
  • Ah right, i get it now. I did not implement all members of your linked class but i guess i could to do this :) Thanks a lot mate! – Ken de Jong Apr 16 '13 at 08:58
0

You should use the overloaded constructor:

Dictionary<TKey, TValue>(IDictionary<TKey, TValue>, IEqualityComparer<TKey>)

instead of using autoproperty, use a backup field.

David
  • 15,894
  • 22
  • 55
  • 66