0

I am using C#, .Net 4.0, and I want to do the simple task of duplicating an Item in a dictionary (with a different key obviously).

I am running into a few problems.

When I make the initial copy, I have no problems. When I change the value of the copy, the value of the original also changes. Why is this?

private void CopyItem(Guid newItemKey, Guid oldItemKey)
{    
    this.dictionary[newItemKey] = this.dictionary[oldItemKey];
    this.dictionary[newItemKey].Id = newItemKey;
}

// this.dictionary[oldItemKey].Id is now equal to newItemKey... Why?

I have also tried:

private void CopyItem(Guid newItemKey, Guid oldItemKey)
{    
    var value = this.dictionary[oldItemKey];
    value.Id = newItemKey;
    this.dictionary[newItemKey] = value;
}

// this.dictionary[oldItemKey].Id is now equal to newItemKey... Why?

I still get the same result.

leppie
  • 115,091
  • 17
  • 196
  • 297
Chris
  • 435
  • 7
  • 19
  • 2
    Presumably Dictionary holds some reference type. You need to [read this](http://www.albahari.com/valuevsreftypes.aspx). [Also this](http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c) – Sriram Sakthivel Aug 24 '15 at 10:53
  • 4
    What is the type of the item? If it is a reference type then you are not making a copy of the item, you are making a copy of the reference, they both reference the same object. – Ben Robinson Aug 24 '15 at 10:53
  • 2
    The problem is indeed that both values are just references to the same object. The question **I** would ask is why do you want to copy stuff anyway? You should almost never want to do this in any program since it's an ugly task that is bound to give you headaches. Most likely, you're thinking of a wrong solution to a problem. – MarioDS Aug 24 '15 at 11:02
  • Cheers guys hadn't considered that – Chris Aug 24 '15 at 11:26

4 Answers4

3

You aren't creating a copy. You are using the same item just a different reference to it. In order to copy a reference type you must use the new keyword and set all the properties of the new object to be equal to the old one. If you hold the source code of the reference type you could also implement ICloneable.

Your code should look something like :

    private void CopyItem(Guid newItemKey, Guid oldItemKey)
    {    
        // Assuming you implemented ICloneable..
        this.dictionary[newItemKey] = this.dictionary[oldItemKey].Clone(); 

        this.dictionary[newItemKey].Id = newItemKey;
    }
Christo S. Christov
  • 2,268
  • 3
  • 32
  • 57
3

This is because if your Dictionary holds a reference type as value, you won't copy the that reference type value but instead you're just re-assigning it. So if you start with a dictionalry like this

[key1][reference_to_0x008B]

and you copy the dictionary-value to another key, it will just copy the reference itself leading to the following dictionary:

[key1][reference_to_0x008B]
[key2][reference_to_0x008B]

So you'll see the references point to a place in your memory where the same object is located for both keys. Manipulating the object afterwards, you'll get these modifications for both keys afterwards.

In short: The referenced object is NOT cloned automatically, it's just the pointer to it. So you'll have to perform a copy by yourself but this can be very tricky (depending on your needs) - see this article for example.

Waescher
  • 5,361
  • 3
  • 34
  • 51
1

You'll need to clone the dictionary as the references point to the same memory locations, see the following post for methods to do this.

What is the best way to clone/deep copy a .NET generic Dictionary<string, T>?

Following quote is one of the answers Jon gave

public static Dictionary<TKey, TValue> CloneDictionaryCloningValues<TKey, TValue>
    (Dictionary<TKey, TValue> original) where TValue : ICloneable
 {
     Dictionary<TKey, TValue> ret = new Dictionary<TKey, TValue>(original.Count,
                                                        original.Comparer);
     foreach (KeyValuePair<TKey, TValue> entry in original)
     {
         ret.Add(entry.Key, (TValue) entry.Value.Clone());
     }
     return ret;
}
Community
  • 1
  • 1
3dd
  • 2,520
  • 13
  • 20
0

Currently when you are copying the object, it is shallow copy, that is the reason,

you should require Deepcopy for reference object (ex. class), you can achieve it by writing your clone function following way.

 public static T DeepCloneCopy<T>(T obj)
    {
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;

            return (T)formatter.Deserialize(ms);
        }
    }
Kunal Khatri
  • 451
  • 3
  • 12