14

I have class called Employee with 3 property called ID,Name,Dept. I need to implement the Copy and Clone method? When I am using Copy or Clone method I need to avoid Casting? how will I do that?.

example: same as DataTable which is having DataTable.Copy() and DataTable.Clone().

Liam
  • 27,717
  • 28
  • 128
  • 190
Kishore Kumar
  • 21,449
  • 13
  • 81
  • 113

6 Answers6

15

You need to implement IClonable interface and provide implementation for the clone method. Don't implement this if you want to avoid casting.

A simple deep cloning method could be to serialize the object to memory and then deserialize it. All the custom data types used in your class need to be serializable using the [Serializable] attribute. For clone you can use something like

  public MyClass Clone()
    {
        MemoryStream ms = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();

        bf.Serialize(ms, this);

        ms.Position = 0;
        object obj = bf.Deserialize(ms);
        ms.Close();

        return obj as MyClass;
    }

If your class only has value types, then you can use a copy constructor or just assign the values to a new object in the Clone method.

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Midhat
  • 17,454
  • 22
  • 87
  • 114
  • Wow that's a complex way of doing it - why not just use a copy constructor? – Rowland Shaw Nov 11 '10 at 09:05
  • @Rowland it wont work on reference types. edited my answer anyhow – Midhat Nov 11 '10 at 09:13
  • 1
    @Rowland - a copy constructor probably wouldn't deep-copy stuff, and it needs maintenance as fields are added. Binary serialization is a very common way of doing deep copies. – Will Dean Nov 11 '10 at 09:13
  • 1
    Technically C# doesn't have copy constructors. You can write a constructor that takes a parameter of the same type and manually copy the properties, but if you want to do a deep copy that can get a bit cumbersome. – Michael Shimmins Nov 11 '10 at 09:14
  • 1
    It seems wasteful (extra memory and CPU usage) to do serialization+deserialization to do cloning, but it certainly has appeal simplicity-wise - compared to either reflecting the whole object graph or adding clone support all the way down the graph (which isn't possible if you don't control every subclass). – snemarch Nov 11 '10 at 09:32
  • 1
    @Will I agree that a copy constructor needs to be implemented on all classes in the object tree; but similarly you have to check that every class is serializable, too. – Rowland Shaw Nov 11 '10 at 11:09
  • 3
    @Rowland - at least you get an exception if they're not! – Will Dean Nov 11 '10 at 11:13
3

Do you have to use the ICloneable interface or is it enough if you just have two methods called Clone and Copy that is defined in a generic interface?

public class YourClass : ICloneable<YourClass>
{
    // Constructor logic should be here
    public YourClass Copy() { return this; }        
    public YourClass Clone() { return new YourClass(ID, Name, Dept); }
}

interface  IClonable<T>
{
    T Copy();
    T Clone();
}

Or have I misunderstood something?

What I am trying to say is that you don't have to make it more complex than it is? If you need your objects to conform to somekind of you can write it yourself if the one specified in the .Net framework is to complex for the situation. You should also define the difference with Clone and Copy, that is, what do they mean to you? I know there are several sites specifying that Clone is a deep copy and Copy is a shallow copy.

Tomas Jansson
  • 22,767
  • 13
  • 83
  • 137
  • 2
    The only issue with that is the maintenance overhead. If you add a new field you need to update your `CopyClone()` method to incorporate it (as well as the constructor it calls). If you're going to call a constructor, rather than passing discrete fields, you should pass the entire object, ie: `return new YourClass(this)` – Michael Shimmins Nov 11 '10 at 09:16
  • @Michael, that is of course true. But the point is to not make it more complicated than it is until you really need it. And the Copy method is probably wrong (will change it :)). You could probably change the IClonable interface I have to an abstract class that contains a Clone method that uses reflection or the serialization pattern that Midhat has written below. – Tomas Jansson Nov 11 '10 at 09:21
  • even iam confused about the documentation from diff. site?. – Kishore Kumar Nov 11 '10 at 10:10
  • Don't be confused, instead figure out your needs. Why do you want to copy/clone? Do you need it for all your objects? Do you want special logic for the copy/clone? Answer those question then implement the solution that fits your needs. One nice feature that you could do is make the IClonable abstract and then use a generic clone method that use reflection. That clone method could take a params parameter for properties to exclude or include, see the `MapRow` method here: http://blog.tomasjansson.com/2010/10/generic-mapper-for-datareader/ for an example of how that include/exclude could work. – Tomas Jansson Nov 11 '10 at 12:06
  • Thomas' original post stated _"I know there are several sites specifying that Clone is a deep copy"_. I think this is a dangerous assumption. Case in point, the MSDN states that _"An implementation of Clone can perform either a deep copy or a shallow copy."_ SOURCE: [ICloneable.Clone Method](https://msdn.microsoft.com/en-us/library/system.icloneable.clone(v=vs.110).aspx) – Pressacco May 20 '16 at 16:32
  • @Pressacco, why is that dangerous? I also say: "_You should also define the difference with Clone and Copy, that is, what do they mean to you?_" The point is that you should know what you mean when you say copy and clone, and be consistent. – Tomas Jansson Jun 21 '16 at 07:51
  • @Thomas: My objective was to simply underscore the fact that regardless of what other websites are stating, as a developer you need to be 100% certain what `Clone()` and `Copy()` mean when you use a third party library. As you have re-iterated, the meaning is implementation specific. Believe me when I say, I am not trying to start an argument on semantics. – Pressacco Jun 21 '16 at 19:21
3

Do you mean, how to implement ICloneable.Clone() and have it return the type of the class itself.

public class MyType : ICloneable
{
  public MyType Clone() //called directly on MyType, returns MyType
  {
    return new MyType(/* class-dependant stuff goes here */);
  }
  object ICloneable.Clone() // called through ICloneable interface, returns object
  {
    return Clone();
  }
}
Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
2

Here an example:

namespace XXX
{
     [Serializable]
    public class ItemChecklist : ICloneable
    {

       // [...here properties, attributes, etc....]



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


    }
}

i.e If you use this function, you will have in "itemAdd" a entire copy of the object "itemTemp" with all its values.

ItemChecklist itemAdd = itemTemp.Clone();
Liz Barraza
  • 133
  • 1
  • 7
2

Check this Object Cloning Using IL in C# http://whizzodev.blogspot.com/2008/03/object-cloning-using-il-in-c.html

Stefan P.
  • 9,489
  • 6
  • 29
  • 43
  • Also only does shallow copy, if you need deep copy you'll have to edit the IL generator to recursively navigate through the graph. – Michael Shimmins Nov 11 '10 at 09:18
  • there's a newer version available: http://whizzodev.blogspot.com/2008/06/object-deep-cloning-using-il-in-c_20.html –  Nov 11 '10 at 09:36
2

I often see copy constructors suggested as an alternative to a cloning method, but except with sealed classes the behaviors are very different. If I have a type Car, which simply supports properties VIN, BodyColor and BodyStyle, and a derivative type FancyCar, which also supports InteriorFabric and SoundSystem, then code which accepts an object of type Car and use the Car copy constructor to duplicate it will end up with a Car. If a FancyCar is passed to such code, the resulting "duplicate" will be a new Car, which has a VIN, BodyColor, and BodyStyle that match the original car, but which will not have any InteriorFabric or SoundSystem. By contrast, the code were to accept a Car and use a cloning method on it, passing a FancyCar to the code would cause a FancyCar to be produced.

Unless one wants to use Reflection, any cloning method must at its base involve a call to base.MemberwiseClone. Since MemberwiseClone is not a virtual method, I would suggest defining a protected virtual cloning method; you may also want to prevent any child classes from calling MemberwiseClone by defining a dummy nested class of protected scope with the same name (so if a descendent class tries to call base.MemberwiseClone, it wouldn't be interpreted as a nonsensical reference to the dummy class).

supercat
  • 77,689
  • 9
  • 166
  • 211