Creating a copy of an object in C#

727,372

Solution 1

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.

Solution 2

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.

Solution 3

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               

Solution 4

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.

Share:
727,372

Related videos on Youtube

afaolek
Author by

afaolek

SOreadytohelp

Updated on October 08, 2020

Comments

  • afaolek
    afaolek over 3 years

    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?

    • vines
      vines almost 13 years
    • hal9000
      hal9000 almost 7 years
      string json = Newtonsoft.Json.JsonConvert.SerializeObject(myobject); myObjType rCopy = Newtonsoft.Json.JsonConvert.DeserializeObject<myObjType>(jso‌​n);
    • amartin
      amartin almost 6 years
      @hal9000 I have used the serialize/deserialize method. Are there downsides to this over the cloning solutions below? Seems like a straight forward solution.
    • hal9000
      hal9000 almost 6 years
      I haven't experienced any downsides. However I cannot comment on the cloning solutions below. I have not tried them
    • afaolek
      afaolek over 5 years
      @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.
  • Shinigamae
    Shinigamae about 11 years
    This is good in studying. Not for practicing.
  • anar khalilov
    anar khalilov over 10 years
    -1 for not mentioning about shallow/deep cloning and their effects. Without this information, MemberwiseClone() is tricky.
  • jingtao
    jingtao almost 10 years
    The second line of the output should be objectB.val = 20, couldn't edit because the edit is too small
  • crush
    crush almost 10 years
    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).
  • vane
    vane almost 10 years
    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
    vane almost 10 years
    Never mind, I found it. In the .NET documentation they "recommend that ICloneable not be implemented in public APIs". So it's not deprecated, just not recommended to be used.
  • vane
    vane almost 10 years
    @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
    vane almost 10 years
    @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
    vane almost 10 years
    @LeeTaylor As one last point, Microsoft adds the Obsolete 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 warning signifying that it is indeed deprecated. ICloneable does not have the Obsolete attribute applied to it.
  • Saim Rahdari
    Saim Rahdari almost 10 years
    -1 for not mentioning that ICloneable is deprecated, and should not be used.
  • JYL
    JYL over 9 years
    @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). You're more speaking about best pratices than official deprecated status.
  • Roland
    Roland over 9 years
    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.
  • Béranger
    Béranger about 9 years
    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 ?
  • Brent Rittenhouse
    Brent Rittenhouse over 6 years
    ... 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." msdn.microsoft.com/en-us/library/…
  • MetalGeorge
    MetalGeorge about 6 years
    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."
  • christo8989
    christo8989 over 5 years
    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);
  • TamaMcGlinn
    TamaMcGlinn over 5 years
    @BrentRittenhouse your comment is incorrect: ideone.com/gKl6gs
  • Kellen Stuart
    Kellen Stuart over 4 years
    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
  • Taha Ali
    Taha Ali over 2 years
    Good article to understand Deep and Shallow Copy Concept- geeksforgeeks.org/shallow-copy-and-deep-copy-in-c-sharp