230

Please have a look at the code below (excerpt from a C# book):

public class MyClass 
{
    public int val;
}
public struct myStruct 
{
    public int val;
}
public class Program 
{
    private static void Main(string[] args) 
    {
        MyClass objectA = new MyClass();
        MyClass objectB = objectA;

        objectA.val = 10;
        objectB.val = 20;

        myStruct structA = new myStruct();
        myStruct structB = structA;

        structA.val = 30;
        structB.val = 40;

        Console.WriteLine("objectA.val = {0}", objectA.val);
        Console.WriteLine("objectB.val = {0}", objectB.val);
        Console.WriteLine("structA.val = {0}", structA.val);
        Console.WriteLine("structB.val = {0}", structB.val);

        Console.ReadKey();
    }
}

I understands it produces the output below:

objectA.val = 20
objectB.val = 20
structA.val = 30
structB.val = 40

The last two lines of the output I have no problem with, but the first two tell me that objectA and objectB are pointing to the same memory block (since in C#, objects are reference types).

The question is how do make objectB, a copy of objectA so that it points to a different area in memory. I understand that trying to assign their members may not work since those members may be references, too. So how do I go about making objectB a completely different entity from objectA?

wonea
  • 4,783
  • 17
  • 86
  • 139
afaolek
  • 8,452
  • 13
  • 45
  • 60
  • 1
    This might help: http://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an-object-in-net-c-specifically – vines Jul 04 '11 at 09:23
  • 5
    string json = Newtonsoft.Json.JsonConvert.SerializeObject(myobject); myObjType rCopy = Newtonsoft.Json.JsonConvert.DeserializeObject(json); – hal9000 May 24 '17 at 21:33
  • @hal9000 I have used the serialize/deserialize method. Are there downsides to this over the cloning solutions below? Seems like a straight forward solution. – amartin Jul 02 '18 at 01:41
  • I haven't experienced any downsides. However I cannot comment on the cloning solutions below. I have not tried them – hal9000 Jul 03 '18 at 12:22
  • 1
    @SiavashGhanbari That sure was not helpful. That question is still on hold. This particular question has been tagged duplicate. That question is a re-re-re-re-duplicate. – afaolek Sep 26 '18 at 10:01

4 Answers4

198

You could do:

class myClass : ICloneable
{
    public String test;
    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

then you can do

myClass a = new myClass();
myClass b = (myClass)a.Clone();

N.B. MemberwiseClone() Creates a shallow copy of the current System.Object.

ono2012
  • 4,967
  • 2
  • 33
  • 42
BugFinder
  • 17,474
  • 4
  • 36
  • 51
  • 41
    -1 for not mentioning about shallow/deep cloning and their effects. Without this information, `MemberwiseClone()` is tricky. – anar khalilov Jan 17 '14 at 14:57
  • 9
    -1 for not mentioning that ICloneable is deprecated, and should not be used. – Tom Aug 01 '14 at 16:14
  • 156
    @Tom : -1 on your comment (if I could) for not giving any link about your statement, as ICloneable is not marked as Obsolete in [official doc](http://msdn.microsoft.com/library/system.icloneable(v=vs.110).aspx)). You're more speaking about best pratices than official deprecated status. – JYL Oct 16 '14 at 08:34
  • 7
    ... But this would give the same result as the user's original problem. Straight from the docs: "If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object." https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx – Brent Rittenhouse Dec 11 '17 at 18:20
  • 2
    Well.. it's not deprecated as such it's recommended not to be used in public API's where the implementation is not clear for consumers of that API, but for internal usage or open source I think it's ok. What they state is "Because callers of Clone cannot depend on the method performing a predictable cloning operation, we recommend that ICloneable not be implemented in public APIs." – MetalGeorge Mar 07 '18 at 20:01
  • @BrentRittenhouse your comment is incorrect: https://ideone.com/gKl6gs – TamaMcGlinn Nov 22 '18 at 07:27
  • 1
    Good article to understand Deep and Shallow Copy Concept- https://www.geeksforgeeks.org/shallow-copy-and-deep-copy-in-c-sharp/ – Taha Ali Oct 21 '21 at 11:04
149

There is no built-in way. You can have MyClass implement the IClonable interface (but it is sort of deprecated) or just write your own Copy/Clone method. In either case you will have to write some code.

For big objects you could consider Serialization + Deserialization (through a MemoryStream), just to reuse existing code.

Whatever the method, think carefully about what "a copy" means exactly. How deep should it go, are there Id fields to be excepted etc.

H H
  • 263,252
  • 30
  • 330
  • 514
  • 7
    I'm sorry, I know this is a really old post but could you provide a link to documentation that says `ICloneable` is deprecated? I looked at the documentation for .net 4.5 and `ICloneable` doesn't say anything about being deprecated. If it is then I'd like to use something else. – vane Jun 13 '14 at 15:57
  • 15
    Never mind, I found it. In the [.NET documentation](http://msdn.microsoft.com/en-us/library/system.icloneable%28v=vs.110%29.aspx) they "recommend that ICloneable not be implemented in public APIs". So it's not deprecated, just not recommended to be used. – vane Jun 13 '14 at 16:03
  • 20
    @LeeTaylor Deprecated means "express disapproval of" and in the context of software, deprecated mean to express disapproval of being used, absolutely. You can't have an API that is deprecated when it is public and not when it is private. Deprecated API is deprecated and should not be used at all unless absolutely necessary. Microsoft does not say that you should absolutely not use this because it is deprecated (usually providing an alternative), it simply says avoid using it in public APis. – vane Jul 31 '14 at 00:16
  • 2
    @LeeTaylor Wikipedia says "Deprecation is an attribute applied to a computer software feature, characteristic, or practice to indicate that it should be avoided (often because it is being superseded)"; avoided as in avoided entirely, not avoided based on accessibility. – vane Jul 31 '14 at 00:18
  • 52
    @LeeTaylor As one last point, Microsoft adds the [Obsolete](http://msdn.microsoft.com/en-us/library/system.obsoleteattribute%28v=vs.110%29.aspx) attribute to classes, structures, enums, delegates, methods, constructors, properties, fields, events and interfaces that they deem deprecated which causes the compiler to issue a [CS0618](http://msdn.microsoft.com/en-us/library/x5ye6x1e.aspx) warning signifying that it is indeed deprecated. `ICloneable` does not have the `Obsolete` attribute applied to it. – vane Jul 31 '14 at 00:35
  • I hate how `IClonable` => `Clone()` forces you to return `object`. Just asking for a runtime exception. That sort of tells me to not go this route – Kellen Stuart Oct 04 '19 at 05:04
60

The easiest way to do this is writing a copy constructor in the MyClass class.

Something like this:

namespace Example
{
    class MyClass
    {
        public int val;

        public MyClass()
        {
        }

        public MyClass(MyClass other)
        {
            val = other.val;
        }
    }
}

The second constructor simply accepts a parameter of his own type (the one you want to copy) and creates a new object assigned with the same value

class Program
{
    static void Main(string[] args)
    {
        MyClass objectA = new MyClass();
        MyClass objectB = new MyClass(objectA);
        objectA.val = 10;
        objectB.val = 20;
        Console.WriteLine("objectA.val = {0}", objectA.val);
        Console.WriteLine("objectB.val = {0}", objectB.val);
        Console.ReadKey();
    }
}

output:

objectA.val = 10

objectB.val = 20               
Chris
  • 681
  • 1
  • 6
  • 16
Levi_vc
  • 617
  • 4
  • 2
  • 10
    This is good in studying. Not for practicing. – Shinigamae Apr 11 '13 at 04:16
  • The second line of the output should be `objectB.val = 20`, couldn't edit because the edit is too small – jingtao May 20 '14 at 09:44
  • 20
    The problem with copy constructors is that if you add/remove fields, you also have to modify the copy constructor. This can become a maintenance nightmare. Especially for objects with many, many fields (50+ i.e. a DataContract). – crush May 28 '14 at 18:47
  • 2
    I like this Answer. A Clone method returns the class object, so it is a kind of constructor. Then, why call it Clone and not use the class name? Then, why the "maintenance nightmare"? If you need to maintain a large list of fields, this is the best place to do it. About "deprecated": nobody forces you to inherit from the IClonable interface. You could implement a Clone() method without the interface. But after all, I will implement the copy constructor in my project. – Roland Feb 04 '15 at 14:29
  • 1
    I agree with @Roland. Using the new keyword you are sure to create a new object with a different adress. I don't see any problem with it. crush you may prefer to use reflection ? – Béranger May 05 '15 at 15:17
  • I went down this path. I like the solution because it's so explicit but I would prefer to put the details in a method. In my case, I had an extra parameter to dictate if I should also clone a "Children" property. For some reason that tilted me towards using a method. `var objB = objA.Clone(isDeep = false);` – christo8989 Aug 17 '18 at 21:04
13

There's already a question about this, you could perhaps read it

Deep cloning objects

There's no Clone() method as it exists in Java for example, but you could include a copy constructor in your clases, that's another good approach.

class A
{
  private int attr

  public int Attr
  {
     get { return attr; }
     set { attr = value }
  }

  public A()
  {
  }

  public A(A p)
  {
     this.attr = p.Attr;
  }  
}

This would be an example, copying the member 'Attr' when building the new object.

Community
  • 1
  • 1
jgemedina
  • 516
  • 1
  • 4
  • 11