Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dictionary.ContainsKey Always Returns False

Tags:

c#

dictionary

Well i am trying to create a small application that saves some employees Names, Ages as well as salaries. So i decided to use Dictionary in order to set every employee's salary and i came up with that code

Code

var employeeSalaryDictionary = new Dictionary<Employee, int>();
employeeSalaryDictionary.Add(new Employee { Name = "Chuck", Age = 37 }, 1000);
employeeSalaryDictionary.Add(new Employee { Name = "Norris", Age = 37 }, 2000);
employeeSalaryDictionary.Add(new Employee { Name = "Rocks", Age = 44 }, 3000);

Employee employeeToFind = new Employee { Name = "Chuck", Age = 37 };
//or even
Employee employeeToFind = new Employee { Name = "Chuck"};

//Always False...
bool exists = employeeSalaryDictionary.ContainsKey(employeeToFind); 

Employee Class

public class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }
}

However as i commented out or as the topic title states, .ContainsKey always returns me False although i tried both ways as shown in the code.

like image 903
Roman Ratskey Avatar asked Jul 12 '13 21:07

Roman Ratskey


People also ask

How to check if dictionary has key c#?

Syntax: public bool ContainsKey (TKey key); Here, the key is the Key which is to be located in the Dictionary. Return Value: This method will return true if the Dictionary contains an element with the specified key otherwise, it returns false.

Is Dictionary ContainsKey thread safe?

Dictionary is not Thread-Safe.

Is ContainsKey case sensitive?

Remarks. The key is handled in a case-insensitive manner; it is translated to lowercase before it is used.

What does TryGetValue do in c#?

TryGetValue Method: This method combines the functionality of the ContainsKey method and the Item property. If the key is not found, then the value parameter gets the appropriate default value for the value type TValue; for example, 0 (zero) for integer types, false for Boolean types, and null for reference types.


1 Answers

You're not using the Dictionary constructor that takes in the IEqualityComparer<T> and neither have you implemented custom equality on the Employee class.

So right now the dictionary is comparing employees by reference. When you new an employee, you have a different reference, even though e.g. name might be the same.

Probably the easiest way here would be to implement your own IEqualityComparer<Employee>, where you could pick which members will be used for equality comparison, and pass it to the dictionary's constructor.

[EDIT] As promised, snippets:

//ReSharper's courtesy
public sealed class NameAgeEqualityComparer : IEqualityComparer<Employee>
{
    public bool Equals(Employee x, Employee y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(x, null)) return false;
        if (ReferenceEquals(y, null)) return false;
        if (x.GetType() != y.GetType()) return false;
        return string.Equals(x.Name, y.Name) && x.Age == y.Age;
    }

    public int GetHashCode(Employee obj)
    {
        unchecked
        {
            return ((obj.Name != null ? obj.Name.GetHashCode() : 0) * 397) ^ obj.Age;
        }
    }
}

And then:

var employeeSalaryDictionary = new Dictionary<Employee, int>(new NameAgeEqualityComparer());
employeeSalaryDictionary.Add(new Employee { Name = "Chuck", Age = 37 }, 1000);
employeeSalaryDictionary.Add(new Employee { Name = "Norris", Age = 37 }, 2000);
employeeSalaryDictionary.Add(new Employee { Name = "Rocks", Age = 44 }, 3000);

Employee employeeToFind = new Employee { Name = "Chuck", Age = 37 };
bool exists = employeeSalaryDictionary.ContainsKey(employeeToFind); // true!

For completeness, here's name-only comparer (also ReSharper's courtesy):

 public sealed class NameEqualityComparer : IEqualityComparer<Employee>
 {
        public bool Equals(Employee x, Employee y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (ReferenceEquals(x, null)) return false;
            if (ReferenceEquals(y, null)) return false;
            if (x.GetType() != y.GetType()) return false;
            return string.Equals(x.Name, y.Name);
        }

        public int GetHashCode(Employee obj)
        {
            return (obj.Name != null ? obj.Name.GetHashCode() : 0);
        }
  }

But, as you noticed, you have to decide which comparer you will use for key-comparison when you create a dictionary. That can't be changed later on...

like image 123
Patryk Ćwiek Avatar answered Sep 24 '22 02:09

Patryk Ćwiek