JARVIS
JARVIS

Reputation: 855

"An item with same key has already been added" not getting this exception if adding duplicate object as a key in dictionary?

I have just a silly doubt that below is my small piece of code.

IDictionary<string, string> dic = new Dictionary<string, string>();
IDictionary<Demo, string> dic2 = new Dictionary<Demo, string>();
dic.Add("S1", "S1.1");
dic.Add("S1", "S1.1");
Demo d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "1");
d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "2");

So my question is i am getting exception at line no 4 which is correct according to dictionary concept that I can not add duplicate key in Dictionary however when I am trying to do same thing with object and object with same name I am not getting any exception event Dictionary have now two object of same type and same name.

Please help to understand this concept.

Upvotes: 0

Views: 1246

Answers (3)

pwas
pwas

Reputation: 3373

When inserting data into dictionary, Equals is used to check wheter key is unique.

In string Equals is implemented to check its value. That is why you cannot insert two strings into dictionary. What's more string is strange type - technically it is reference type, but acts like value type.

In bare object (or when not overriden), Equals is implemented to compare object by reference - it just checks wheter variabled points to the same area of memory (note: we are talking about classes, not structs :-)). So when you create two objects:

Demo d1 = new Demo() { MyProperty = 1 };
d1 = new Demo() { MyProperty = 1 };

There are two copies of that object in different place in memory, so Equals says: "That objects are different" - and you can add it to the dictionary.

You can of course change this behaviour by overriding Equals (and GetHashCode but here is skipped to keep answer clear) in Demo:

public override bool Equals(object obj)
{
    // If parameter cannot be cast to Demo or is null return false.
    Demo p = obj as Demo;
    if (p == null)
    {
        return false;
    }

    // Return true if the fields match:
    return (MyPropertyx == p.MyProperty));
}

Then:

Demo d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "1");
d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "2");

will not definitely allow to insert second value.

Upvotes: 2

Stefan Charsley
Stefan Charsley

Reputation: 1406

In C# strings behave like value types which means that the value of the string is compared (which is called Value Equality), meaning:

var string1 = "S1";
var string2 = "S1";
Console.WriteLine(string1 == string2) // will output true

In the case of objects (such as your Demo object) by default when they are compared they are only checked to see if they are the same object (which is called Reference Equality), meaning:

var d1 = new Demo() { MyProperty = 1 };
var d2 = new Demo() { MyProperty = 1 };
Console.WriteLine(d1 == d2) // will output false

Now with objects you can implement Value Equality so that the above example will output true.

You can learn more about that with this guideline.

Upvotes: 2

Jamiec
Jamiec

Reputation: 136074

You have two objects using the same variable name (d1) but they refer to different instances of an object - so there is no duplicate.

It also looks like you expect both objects to be the "same" based on both having a property MyProperty with the value 1. This is not the case - the dictionary, by default, will use the references as the key, which are different as I mentioned above. To enable the dictionary to treat your two objects as the same you would need to override Equals and GetHashCode in your class Demo

Upvotes: 1

Related Questions