Leon Barkan Leon Barkan - 1 month ago 8
C# Question

How to make Dictionary find object key by value

In my application i need to use custom object as a key for dictionary.
The problem is compare by reference,
like we all know when using value types the compare work comparing by values but in objects it's compare by reference so even if the objects are equal they sored in different places in memory heap so it returns false

to do it right i need to override Equals and GetHashCode methods (i think correct me if i'm wrong)

i override the Equals Method and it's working:

bool IsEqual = dictionaryList.Keys.First().Equals(compareKey);
returns true.

what i didn't know is how to override the GetHashCode method (and if i need) to my case.

Exception that i get :

The given key was not present in the dictionary.
-


The given key was not present in the dictionary.


How can i solve that issue or maybe i doing it completely in wrong way...

using System;
using System.IO;
using System.Threading;
using System.Linq;
using System.Collections.Generic;

public sealed class Program
{
public class Options
{
public string x { get; set; }
public string y { get; set; }
}

public class Data
{
public string myData { get; set; }
}

public class KeyClass
{
public int KeyNumber { get; set; }
public List<Options> Options { get; set; }

public override bool Equals(object obj)
{
KeyClass keyClass = obj as KeyClass;

bool IsKeyNumberEqual = (KeyNumber == keyClass.KeyNumber);
bool IsOptionsEqual = true;

if (!(Options.Count == keyClass.Options.Count) || !IsKeyNumberEqual)
{
IsOptionsEqual = false;
}
else
{
for (int i = 0; i < Options.Count; i++)
{
if (!(Options[i].x == keyClass.Options[i].x) ||
!(Options[i].y == keyClass.Options[i].y))
{
IsOptionsEqual = false;
break;
}
}
}

return (IsKeyNumberEqual && IsOptionsEqual);
}
}

public static void Main()
{
try
{
List<Options> optionsList = new List<Options>();
optionsList.Add(new Options() { x = "x1", y = "y1" });
optionsList.Add(new Options() { x = "x2", y = "y2" });

Data someData = new Data() { myData = "someData" };
Data getData = new Data();

KeyClass dictionaryKey = new KeyClass() { KeyNumber = 1, Options = optionsList };
KeyClass compareKey = new KeyClass() { KeyNumber = 1, Options = optionsList };

Dictionary<KeyClass, Data> dictionaryList = new Dictionary<KeyClass, Data>();

dictionaryList.Add(dictionaryKey, someData);

bool IsEqual = dictionaryList.Keys.First().Equals(compareKey);

getData = dictionaryList[compareKey];
}
catch (Exception ex)
{
string exMessage = ex.Message;
}


}
}

Answer

You need to write a GetHashCode() that includes everything that contributes to the Equals() method.

For example:

public override int GetHashCode()
{
    unchecked
    {
        int hash = KeyNumber * 397;

        foreach (var opt in Options)
        {
            hash = hash*23 + opt.x.GetHashCode();
            hash = hash*23 + opt.y.GetHashCode();
        }

        return hash;
    }
}