62

When I do the following.. anything done to Person b modifies Person a (I thought doing this would clone Person b from Person a). I also have NO idea if changing Person a will change Person b after the linking. Due to my code right now, I can only see this in 1 direction.

Person a = new Person() { head = "big", feet = "small" };
Person b = a; 

b.head = "small"; //now a.head = "small" too   

Now if I do this instead.. Person a becomes completely separate.

Person b = new Person() { head = a.head, feet = a.feet };

Now this fine and kinda makes sense when comparing this behaviour to other things in C#. BUT, this could get very annoying with large objects.

Is there a way to shortcut this at all?

Such as:

Person b = a.Values;

John Saunders
  • 160,644
  • 26
  • 247
  • 397
PiZzL3
  • 2,092
  • 4
  • 22
  • 30
  • Can you give an example of what you're trying to accomplish with this? This isn't the sort of thing that's needed frequently. Maybe there's another way to accomplish your task. – John Saunders Mar 19 '11 at 01:17
  • It is called "deep copy", search for this. Your example is a very good one for why you rarely actually do this. The odds that one person would have the exact same traits as another one are quite rare. – Hans Passant Mar 19 '11 at 01:18
  • Note that the word "linking" is not used for what you're doing there. This is an assignment. The question header implies that the question has something to do with the linker. – steinar Mar 19 '11 at 01:22
  • Sorry about the terminology, I don't know how to properly define everything yet. I'm basically storing a bunch of settings in a object. Then another object takes those settings and builds itself from them. Unfortunately (for me right now), building the second object changes the first object because of this behavior. Maybe I shouldn't be storing my settings in an object, but I don't know how else to do it because of how complex it is. – PiZzL3 Mar 19 '11 at 01:30
  • This isn't a link at all. They're the same object. You've got two references to the same object. – John Saunders Mar 19 '11 at 01:30
  • possible duplicate of [Deep cloning objects](http://stackoverflow.com/questions/78536/deep-cloning-objects) – Chris Moschini Aug 11 '14 at 09:26

16 Answers16

70

What you are looking is for a Cloning. You will need to Implement IClonable and then do the Cloning.

Example:

class Person() : ICloneable
{
    public string head;
    public string feet; 

    #region ICloneable Members

    public object Clone()
    {
        return this.MemberwiseClone();
    }

    #endregion
}

Then You can simply call the Clone method to do a ShallowCopy (In this particular Case also a DeepCopy)

Person a = new Person() { head = "big", feet = "small" };
Person b = (Person) a.Clone();  

You can use the MemberwiseClone method of the Object class to do the cloning.

Shekhar_Pro
  • 18,056
  • 9
  • 55
  • 79
  • 5
    Do not use IClonable: http://blogs.msdn.com/b/brada/archive/2003/04/09/49935.aspx – Robert Levy Mar 19 '11 at 01:26
  • 4
    @Robert Levy: I know the difference arise between Shallow Copy and Deep Copy, when you have Reference type of members in the class. – Shekhar_Pro Mar 19 '11 at 01:32
  • 4
    @RobertLevy That link makes no coherent point, except that somebody was frustrated on the internet, long ago. – jpaugh Sep 24 '16 at 16:26
  • 2
    @jpaugh it was easier to read 5 years ago before the formatting of the blog broke but it's basically a post from the dude at Microsoft who wrote the framework design guidelines issuing a guideline that IClonable should not be used because it's contract is ambiguous – Robert Levy Sep 24 '16 at 23:01
  • @RobertLevy Thanks for explaining! I came across another MSDN blog post which I think says the same thing: https://blogs.msdn.microsoft.com/brada/2004/05/03/should-we-obsolete-icloneable-the-slar-on-system-icloneable/ – jpaugh Sep 25 '16 at 01:55
44

Is there a way to shortcut this at all?

No, not really. You'll need to make a new instance in order to avoid the original from affecting the "copy". There are a couple of options for this:

  1. If your type is a struct, not a class, it will be copied by value (instead of just copying the reference to the instance). This will give it the semantics you're describing, but has many other side effects that tend to be less than desirable, and is not recommended for any mutable type (which this obviously is, or this wouldn't be an issue!)

  2. Implement a "cloning" mechanism on your types. This can be ICloneable or even just a constructor that takes an instance and copies values from it.

  3. Use reflection, MemberwiseClone, or similar to copy all values across, so you don't have to write the code to do this. This has potential problems, especially if you have fields containing non-simple types.

recursive
  • 83,943
  • 34
  • 151
  • 241
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 5
    Implementing ICloneable is not recommended. There is no generic version of it. The clone will not have the type of the original, but will be of type object. Also readonly fields cannot be written to from a Clone method. It is better to write a constructor taking the original as parameter. – Peter Huber Apr 30 '16 at 07:59
  • 1
    @PeterHuber you are correct with regard to implementing ICloneable but that does mean that the OP cannot create a Clone method (WITHOUT implementing ICloneable) and make the method return a strongly typed copy of itself instead of an "object". Regardless, it seems like additional work the OP is hoping to avoid. – Andrew Steitz Dec 20 '16 at 17:19
  • 4
    @AndrewSteitz: Indeed, it is perfectly fine just to write a Clone() method returning a Person. I just feel that it is nicer using 'Person clonedPerson = new Person(originalPerson);'. It makes quite clear that a new object of class Person gets returned, while 'originalPerson.Clone()' could return originalPerson. Of course, this doesn't make much sense, but the constructor guarantees that a new object gets returned. – Peter Huber Dec 21 '16 at 10:23
  • @PeterHuber I liked your solution better so went with it, then realized it had an added benefit of being able to use an object initializer: Person clonedPersion = new Person(originalPerson) { HairColor = "Black" }. – Marc Levesque Oct 13 '20 at 16:07
22

I use AutoMapper for this. It works like this:

Mapper.CreateMap(typeof(Person), typeof(Person));
Mapper.Map(a, b);

Now person a has all the properties of person b.

As an aside, AutoMapper works for differing objects as well. For more information, check it out at http://automapper.org

Update: I use this syntax now (simplistically - really the CreateMaps are in AutoMapper profiles):

Mapper.CreateMap<Person, Person>;
Mapper.Map(a, b);

Note that you don't have to do a CreateMap to map one object of the same type to another, but if you don't, AutoMapper will create a shallow copy, meaning to the lay man that if you change one object, the other changes also.

Kasey Krehbiel
  • 423
  • 5
  • 12
  • 1
    Thanks, this works perfect! We already used Mappers in our solution anyway, and this is a better solution than the JSON serialize and deserialize I've also seen, since you are then forced to have a serialized object and it also doesn't work for lists of objects inside it. This is a much better and cleaner solution and it works like a charm. – Kevin Cruijssen Mar 04 '15 at 12:01
  • 1
    if your project is already using automapper, this is imho the way to go. – Souhaieb Besbes Jan 15 '16 at 15:56
21

Since the MemberwiseClone() method is not public, I created this simple extension method in order to make it easier to clone objects:

public static T Clone<T>(this T obj)
{
    var inst = obj.GetType().GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

    return (T)inst?.Invoke(obj, null);
}

Usage:

var clone = myObject.Clone();
tocqueville
  • 5,270
  • 2
  • 40
  • 54
8

To clone your class object you can use the Object.MemberwiseClone method,

just add this function to your class :

public class yourClass
{
    // ...
    // ...

    public yourClass DeepCopy()
    {
        yourClass othercopy = (yourClass)this.MemberwiseClone();
        return othercopy;
    }
}

then to perform a deep independent copy, just call the DeepCopy method:

yourClass newLine = oldLine.DeepCopy();
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Chtioui Malek
  • 11,197
  • 1
  • 72
  • 69
  • 8
    You probably should call it `ShallowCopy`, since it would result in a shallow copy in most cases. (cf. with the examples at https://msdn.microsoft.com/de-de/library/system.object.memberwiseclone(v=vs.110).aspx) – Micha Wiedenmann Dec 18 '17 at 13:06
6

a and b are just two references to the same Person object. They both essentially hold the address of the Person.

There is a ICloneable interface, though relatively few classes support it. With this, you would write:

Person b = a.Clone();

Then, b would be an entirely separate Person.

You could also implement a copy constructor:

public Person(Person src)
{
  // ... 
}

There is no built-in way to copy all the fields. You can do it through reflection, but there would be a performance penalty.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 3
    Do not use IClonable: http://blogs.msdn.com/b/brada/archive/2003/04/09/49935.aspx – Robert Levy Mar 19 '11 at 01:27
  • @Robert, 1. The difference between deep copy and shallow copy is irrelevant here, because the class only has two fields, both with immutable types. 2. I didn't recommend ICloneable. I listed it as an option. 3. That is not an official guideline, just a discussion of a *plan* to add it to the official guidelines (I don't know if it made it). – Matthew Flaschen Mar 19 '11 at 01:37
  • it did make it to the official guidelines – Robert Levy Mar 19 '11 at 02:07
  • @Robert, can you post the official link, so I can see the details? – Matthew Flaschen Mar 19 '11 at 02:47
  • section 8.5 of the book (second edition) http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613/ref=sr_1_1?ie=UTF8&qid=1300505525&sr=8-1 – Robert Levy Mar 19 '11 at 03:32
  • also see http://blogs.msdn.com/b/brada/archive/2004/05/03/125427.aspx which excerpts from this book and the SLAR – Robert Levy Mar 19 '11 at 03:35
5

It couldn't be simpler than this:

    public SomeClass Clone () {

        var clonedJson = JsonConvert.SerializeObject (this);

        return JsonConvert.DeserializeObject<SomeClass> (clonedJson);
    }

Just serialize any object to a JSON string and then deserialize it. This will do a deep copy...

Steve Miller
  • 300
  • 3
  • 11
  • 1
    Could be made to an extension too. ` public static T Clone(this T classToClone) where T : class { // the serialize thing but with generic type } ` – Jane Mar 09 '21 at 15:15
2

You could do it like this:

var jss = new JavaScriptSerializer();
var b = jss.Deserialize<Person>(jss.Serialize(a));

For deep cloning you may want to take a look at this answer: https://stackoverflow.com/a/78612/550975

Community
  • 1
  • 1
Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
  • 1
    You are right, you could but if you do you'd take on a dependency to System.Web.Script.Serialization which may or may not be a bad thing depending on your project type. – rism Aug 15 '14 at 04:01
  • 1
    This approach is very efficient when you want to clone Api objects since you should already have a reference to the serialization class namespace. I personnally used it in a Json context (I had partial classes automatically generated from yaml which had their properties decorated with Json attributes). – Ishikawa Aug 24 '23 at 14:32
2

Painlessly: Using NClone library

Person a = new Person() { head = "big", feet = "small" };
Person b = Clone.ObjectGraph(a); 
StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
magallanes
  • 6,583
  • 4
  • 54
  • 55
2

MemberwiseClone is a good way to do a shallow copy as others have suggested. It is protected however, so if you want to use it without changing the class, you have to access it via reflection. Reflection however is slow. So if you are planning to clone a lot of objects it might be worthwhile to cache the result:

public static class CloneUtil<T>
{
    private static readonly Func<T, object> clone;

    static CloneUtil()
    {
        var cloneMethod = typeof(T).GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        clone = (Func<T, object>)cloneMethod.CreateDelegate(typeof(Func<T, object>));
    }

    public static T ShallowClone(T obj) => (T)clone(obj);
}

public static class CloneUtil
{
    public static T ShallowClone<T>(this T obj) => CloneUtil<T>.ShallowClone(obj);
}

You can call it like this:

Person b = a.ShallowClone();
Tim Pohlmann
  • 4,140
  • 3
  • 32
  • 61
1
  public static T Clone<T>(T obj)
  {
      DataContractSerializer dcSer = new  DataContractSerializer(obj.GetType());
      MemoryStream memoryStream = new MemoryStream();

      dcSer.WriteObject(memoryStream, obj);
      memoryStream.Position = 0;

      T newObject = (T)dcSer.ReadObject(memoryStream);
      return newObject;
  }
Tatinfo
  • 37
  • 4
  • I upvoted because this absolutely DOES what the OP is asking for but serializing/deserializing are very "expensive" operations so anyone reading this, please keep in mind how often you are going to need to perform this. – Andrew Steitz Dec 20 '16 at 17:24
1

Similar to @ChtiouiMalek's answer but with System.Text.Json you can serialize and deserialize to get a deep clone of your object, e.g.

    string json = JsonSerializer.Serialize<Person>(person);
    Person personClone = JsonSerializer.Deserialize<Person>(json);

And, of course, you can do it as a 1-liner:

    Person personClone = JsonSerializer.Deserialize<Person>(
        JsonSerializer.Serialize<Person>(person));
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
0

In my opinion, the best way to do this is by implementing your own Clone() method as shown below.

class Person
{
    public string head;
    public string feet;

    // Downside: It has to be manually implemented for every class
    public Person Clone()
    {
        return new Person() { head = this.head, feet = this.feet };
    }
}

class Program
{
    public static void Main(string[] args)
    {
        Person a = new Person() { head = "bigAF", feet = "smol" };
        Person b = a.Clone();

        b.head = "notEvenThatBigTBH";

        Console.WriteLine($"{a.head}, {a.feet}");
        Console.WriteLine($"{b.head}, {b.feet}");
    }
}

Output:

bigAf, smol

notEvenThatBigTBH, smol

b is totally independent to a, due to it not being a reference, but a clone.

Hope I could help!

Community
  • 1
  • 1
Wahoo
  • 1
  • 2
0

This code worked for me. It also takes a very small amount of time to execute.

    public static void CopyTo(this object Source, object Destination)
    {
        foreach (var pS in Source.GetType().GetProperties())
        {
            foreach (var pT in Destination.GetType().GetProperties())
            {
                if (pT.Name != pS.Name) continue;
                (pT.GetSetMethod()).Invoke(Destination, new object[]
                { pS.GetGetMethod().Invoke( Source, null ) });
                break;
            }
        };
    }
0
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
public static T? FromJson<T>(this string json) => JsonSerializer.Deserialize<T>(json, _jsonOptions);
public static string ToJson<T>(this T obj) where T : class => JsonSerializer.Serialize(obj, _jsonOptions);
public static T? Clone<T>(this T obj) where T : class => obj.ToJson().FromJson<T>();

This is how I have solved it using the built in Json class and created some extension methods. These extension methods come in handy all over my project. (This is running on .NET 6)

Josh
  • 1
-2

This happens because "Person" is a class, so it is passed by reference. In the statement "b = a" you are just copying a reference to the one and only "Person" instance that you created with the keyword new.

The easiest way to have the behavior that you are looking for is to use a "value type".

Just change the Person declaration from

class Person

to

struct Person
Maghis
  • 1,093
  • 1
  • 7
  • 15