Search code examples
c#.netlinqdictionaryexcept

Using Except on Dictionaries with Object as Value


until now i had 2 dictionaries of type Dictionary<string, int> and needed to get everything which is in dict1 but not in dict2 using except. Example:

Dictionary<string, int> dict1 = new Dictionary<string, int>
{
    { "aaa", 1 },
    { "bbb", 2 }
};

Dictionary<string, int> dict2 = new Dictionary<string, int>
{
    { "aaa", 2 },
    { "bbb", 2 }
};

var newDict = dict1.Except(dict2);

newDict now contains { "aaa", 1 } which is what i expect, because the value is different.

My problem is, that we needed an additional value in the dictionary so we changed Dictionary<string, int> to Dictionary<string, MyObject>. When i use except now, i don't get the result i'd like to. Example:

public class MyObject
{
    public MyObject(string name, int someNumber)
    {
        myString = name;
        myInt = someNumber;
    }

    public string myString { get; set; }
    public int myInt { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, MyObject> dict1 = new Dictionary<string, MyObject>
        {
            { "aaa", new MyObject("abc", 1) },
            { "bbb", new MyObject("def", 2) }
        };

        Dictionary<string, MyObject> dict2 = new Dictionary<string, MyObject>
        {
            { "aaa", new MyObject("abc", 2) },
            { "bbb", new MyObject("def", 2) }
        };

        var newDict = dict1.Except(dict2);
    }
}

newDict now contains all kvp from dict1, but i actually only want to have the first entry from dict1. I think that is because values of MyObject are not being compared. What can i do to solve this? Is there maybe an easy way via Linq?

Thanks in advance!


Solution

  • You need to implement object.Equals(object other) in your MyObject.

    Depending on how you define equality between your objects, it could look like this:

    public override bool Equals(object other)
    {
        if(!(other is MyObject))
        {
            return false;
        }
        var o = other as MyObject;
        return myString.Equals(o.myString) && myInt == o.myInt;
    }
    

    As René says in the comment, it usually is a good idea to also implement GetHashCode when you implement Equals.