Dictionary.ContainsKey return False, but a want True

namespace Dic
{
public class Key
{
    string name;
    public Key(string n) { name = n; }
}

class Program
{
    static string Test()
    {
        Key a = new Key("A");
        Key b = new Key("A");
        System.Collections.Generic.Dictionary<Key, int> d = new System.Collections.Generic.Dictionary<Key, int>();
        d.Add(a, 1);
        return d.ContainsKey(b).ToString();
    }

    static void Main(string[] args)
    {
        System.Console.WriteLine(Test());
    }
}
}

What should I change to get true?


Solution 1:

You want true - but a and b are different objects.

You need to override GetHashCode and Equals on class Key

public class Key
{
    string name;
    public Key(string n) { name = n; }

    public override int GetHashCode()
    {
        if (name == null) return 0;
        return name.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        Key other = obj as key;
        return other != null && other.name == this.name;
    }
}

Solution 2:

It would probably help if you override Key.GetHashCode and Key.Equals.

In Key:

public override bool Equals(object obj)
{
    var k = obj as Key;
    if (k != null)
    {
        return this.name == k.name;
    }
    return base.Equals(obj);
}

public override int GetHashCode()
{
    return this.name.GetHashCode();
}

Solution 3:

If you do not have the ability to override equality operators/Equals/GetHashCode as others have mentioned (as in, you do not control the source code of the object), you can provide an IEqualityComparer<Key> implementation in the constructor of the dictionary to perform your equality checks.

class KeyComparer : IEqualityComparer<Key>
{
    public bool Equals(Key x, Key y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(Key obj)
    {
        return obj.Name.GetHashCode();
    }
}

As it stands, your Key is a reference object, so equality is only determined on reference unless you tell the world (or the dictionary) otherwise.