This explanation is not valid for immutable classes (strings, delegates, structures, etc), because these classes have other behaviors, and do not feature in this article.
For this, we will use two implementation techniques - ICloneable Interface and Extension Methods, depending on the type of cloning.
Class example
This is the class we will use for the examples.
- public class Customer : ICloneable
- {
- public int ID { get; set; }
- public string Name { get; set; }
- public decimal Sales { get; set; }
- public DateTime EntryDate { get; set; }
- public Address Adress { get; set; }
- public Collection<string> Mails { get; set; }
-
- protected string Data1 { get; set; }
- private string Data2 { get; set; }
-
-
- public Customer()
- {
- Data1 = "data1";
- Data2 = "Data2";
- }
-
-
-
- public virtual object Clone() { }
-
- }
The need of cloning
It is a very essential programmatic part. If you are not a basic developer, you can skip this blog. In the high level languages (C#, Java, C++, etc.), when we assign an object to another object, we are assigning two objects to the same reference.
- Customer customer1 = new Customer { ID = 1, Name = "Test", City = "City", Sales = 1000m };
- Customer customer2 = customer1;
Customer1 and Customer2 are linked and any modification in an object will be reflected in the other object. To Clone is necessary for un-linking the object and its virtual copy; and they are independent objects.
ICloneable
It is an official .NET Framework Interface to clone the objects. It is very simple and has only one method, Clone. This interface leaves you free to use the Clone method as we like. We can apply the depth level we choose.
- public interface ICloneable
- {
- object Clone();
- }
The biggest problem of this interface is the return value of Clone method, object type. Whenever you use the Clone method, you will have to do a casting to principal type.
- Customer customer2 = (Customer)customer1.Clone();
Extension Method
Another way to clone objects is by Extension Methods. These methods provide an opportunity to return generic types. With this, we save the boxing/unboxing problems. We write the Extensions Methods only once, and we may use our extension method extending object for all .NET types.
- public static class MyExtensions {
- public static T CloneObject < T > (this object source) {
- T result = Activator.CreateInstance < T > ();
-
- return result;
- }
- }
Call - Customer Customer2 = customer1.CloneObject();
We can use the extension method in conjunction with ICloneable.
- public class Customer: ICloneable {
-
- public virtual object Clone() {
- return this.CloneObject();
- }
- }
Object.MemberWiseClone
MemberWiseClone is a protected method of object. This method creates a shallow copy of current object to the new object.
MemberWiseClone copies the references properties (classes) or values properties (structs), in a different way
- Structs Copies bit by bit the value of property.
- Class Copies the reference of property, consequently they are the same object.
The case class is a problem, because both objects are the same. This is a lack of method.
The use of MemberWiseClone is usually done at the same as ICloneable Interface, because the MemberWiseClone is a protected method and is mandatory to call internally.
MemberWiseClone example
- public class Customer: ICloneable {
- public int ID {
- get;
- set;
- }
- public string Name {
- get;
- set;
- }
- public decimal Sales {
- get;
- set;
- }
- public DateTime EntryDate {
- get;
- set;
- }
- public Address Adress {
- get;
- set;
- }
- public Collection < string > Mails {
- get;
- set;
- }
- protected string Data1 {
- get;
- set;
- }
- private string Data2 {
- get;
- set;
- }
- public Customer() {
- Data1 = "data1";
- Data2 = "Data2";
- }
- public virtual object Clone() {
- return this.MemberwiseClone();
- }
- }
Pros - Easy for developers.
- Very little code to write.
- Easy to understand.
- It copies any fields/properties type (simple and complex).
- It doesn’t need to mark the class with any special attribute.
Cons
- It can be called inside the class only, because it is a protected method.
- It must be implemented in all classes to clone.
- The reference properties of object to clone can't be copied, they are linked.
- The clone method returns object, consequently we will have to do casting each time we use it.
If we try a completely in-depth copy, we have to do manual assignments of all references properties,
- public virtual object Clone()\
- {
- var result = this.MemberwiseClone();
-
- result.Adress = new Address {
- City = this.Adress.City,
- Street = this.Adress.Street,
- ZipCode = this.Adress.ZipCode
- };
- result.Mails = new Collection < string > ();
- this.Mails.ToList().ForEach(a => result.Mails.Add(a));
- return result;
- }
Stream - Formatters
This cloning type uses serialization to process the object's copies. It makes in depth copies but forces you to mark the class objects with any serialization attribute.
In this site, there is a very good example from our companion Surajit Datta Article, we will take this code for our example.
Since we don’t write this code in all clone classes, we will create an Extension Method.
- public static T CloneObjectSerializable < T > (this T obj) where T: class {
- MemoryStream ms = new MemoryStream();
- BinaryFormatter bf = new BinaryFormatter();
- bf.Serialize(ms, obj);
- ms.Position = 0;
- object result = bf.Deserialize(ms);
- ms.Close();
- return (T) result;
- }
Call
- Customer customer2 = customer1.CloneObjectSerializable();
If running this code, it throws SerializationException:
To prevent these errors, we mark the class with Serialization Attribute.
- [Serializable]
- public class Customer
Pros - Easy for developer
- Easy to write in an Extension Method, therefore we implement once.
- It copies any fields/properties types (simple and complex)
- It implements deep copy.
- It doesn’t necessary call inside the class, because it is an object extension method.
- Returns a Generic Type, therefore we don't hav to apply boxing / unboxing.
Cons
- It needs to mark with special attribute.
- For your implementation it needs more code and logic.
This method can be use with ICloneable, which perfectly maintains all of its virtues.
- public virtual object Clone()
- {
- return this.CloneObjectSerializable();
- }
Conclusions
There isn’t a magic way to clone objects in .NET Framework, but these two models make the work easier. In the development world, it's necessary to be clear about cloning objects, this misunderstanding is often the consequence of errors and unexpected behaviors in our programs.