6

I have an object like 'obj1' which I want to add to a list. I can add it by just list1.add(obj1) .Now once I update obj1, the object in my list is also updating! (I understand that I am dealing with references here)

My requirement demands modifying the obj1 and add it to the list again! Instead of having two different objects, I have only one, because for both of them, the reference is the same - obj1.

Is there any way I can modify this obj1 and add it to the list and still not lose the old one? Any workarounds would be extremely helpful!

Thanks in Advance!

D.R.
  • 20,268
  • 21
  • 102
  • 205
Krishna
  • 425
  • 3
  • 6
  • 14
  • 1
    Create an new obj1 after you insert it into list or use Cloning (ICloneable) or use a ValueType instead if possible. – Jehof Mar 20 '14 at 07:27

3 Answers3

7

The C# language does not support cloning of objects. Therefore, if obj1 is not a value object (i.e. a struct), you cannot do that. Note: there is the possibility of implementing ICloneable, however, its use is not advised.

One approach I use in another project is to use AutoMapper to create a copy of the object before inserting into the list. Example:

MyType copy = Mapper.DynamicMap(obj1);
list.Add(copy);

Please use that approach for value holder types only, especially not for types that implement IDisposable or something similar.

Community
  • 1
  • 1
D.R.
  • 20,268
  • 21
  • 102
  • 205
5

I found a way to do it with out AutoMapper. While AutoMapper looks like a great tool, I was unable to use it in my project which requires Net2.0/Mono.

You can use a serializer to create a copy/clone of an object. I used json.NET since I was using it already in my project, but I imagine other libraries would work as well. Basically, you serialize the object into a string, and then create a new object from that string, since the string isn't tied to the original object, you get a completely new object.

Here is an example of code using json.net:

List<SomeObject> list1 = new List<SomeObject>();
SomeObject obj1 = new SomeObject(params, etc);

string data = JsonConvert.SerializeObject(obj1);
SomeObject obj2 = JsonConvert.DeserializeObject<SomeObject>(data);
list1.Add(obj2);

You could even shorten the last three lines down to something like this:

list1.Add(JsonConvert.DeserializeObject<SomeObject>(JsonConvert.SerializeObject(obj1)));

You could probably write a function/method to do this for you. Since I was making my own object types, I added one to the object which looked like this:

public ItemInputData copyOf()
{
    string data = JsonConvert.SerializeObject(this);
    ItemInputData copy = JsonConvert.DeserializeObject<ItemInputData>(data);
    return copy;
}

And the code for adding a copy to the list looked like this:

list1.Add(item.copyOf());

Hope this helps =]

chimeforest
  • 51
  • 1
  • 5
0

From what I've read from the C# 6.0 Cookbook, the best way to do this is to create your own ShallowClone and DeepClone interfaces, then implement them. The reason it's not suggested to use ICloneable is due to the confusion around whether or not ICloneable creates a DeepClone or a ShallowClone, so instead make your own interfaces if Microsoft's don't work.

ShallowClone is recreating the object with all it's properties having the same reference (two different objects referencing the same properties)

DeepClone is recreating the object with new properties.

To do the ShallowClone, the following works:

public ShallowClone ShallowCopy() => (ShallowClone)this.MemberwiseClone();

And for the DeepClone:

public DeepClone DeepCopy()
{
 BinaryFormatter BF = new BinaryFormatter();
 MemoryStream memStream = new MemoryStream();
 BF.Serialize(memStream, this);
 memStream.Flush();
 memStream.Position = 0;
 return (DeepClone)BF.Deserialize(memStream);
}

Stolen straight from the book, so all credit goes there. I just remember that this is the way it "should" be done in C#. There may still be a better way however, especially seen as we're at C# 8.0 now.

You can just write your own ShallowClone and DeepClone methods, and assign each property or create new properties, but this is tedious, hence why the above methods are so useful.

So the idea is you implement these interfaces on the objects you want to clone, and then use the methods.

I was thinking of making these extension methods instead, but it doesn't work. My idea was something like:

public static class CloningExtention
{
    public static T ShallowClone(this T obj) => (T)obj.MemberwiseClone(); // Doesn't work

    public static T DeepClone(this T obj)
    {
        BinaryFormatter BF = new BinaryFormatter();
        MemoryStream memStream = new MemoryStream();
        BF.Serialize(memStream, this);
        memStream.Flush();
        memStream.Position = 0;
        return (T)BF.Deserialize(memStream);
    };
}

But MemberwiseClone is a protected method, so extension methods don't work. Why is it protected? I have no idea, but if I had to guess, it'd be because there is a very good reason why you shouldn't be cloning objects anywhere you like.

However, I still wanted to demonstrate it, so you know not to do it. If anyone knows why this method is protected, please let me know.

DubDub
  • 1,277
  • 1
  • 10
  • 24