Click here to Skip to main content
16,016,489 members
Articles / Programming Languages / C#

Cloning Objects in .NET Framework - Part I

Rate me:
Please Sign up or sign in to vote.
4.61/5 (29 votes)
11 Apr 2017CPOL4 min read 64.8K   24   21
The importance of cloning objects in .NET Framework

Introduction

In this article, we will be showing many ways to clone objects in .NET Framework. Each mode to clone will analyze the pros and cons.

This explanation is not valid for Immutable class (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, first of all, the ICloneable Interface, secondly extension methods depending on the type of cloning.

Background

It is a very essential programmatic part. If you are not a basic developer, you can skip this block.

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:

C#
Customer customer1 = new Customer { ID = 1, Name = "Test", City = "City", Sales = 1000m };
Customer customer2 = customer1;

Image 1

Customer1 and Customer2 are linked and any modification in an object will be reflected in the other object.

To Clone is necessary for unlinking the object and its virtual copy and they are independent objects.

C#
Customer customer2 = (Customer)customer1.Clone();

Image 2

Class for Examples

This is the class we will use for the examples:

C#
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() { }
}

ICloneable

It is an official .NET Framework Interface to Clone 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 any depth level we choose.

C#
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:

C#
Customer customer2 = (Customer)customer1.Clone();

Extension Method

Another way to clone objects is by Extension Methods. These methods provide an opportunity to return generics types, with this, we save the boxing/unboxing problems. We write the Extensions Methods only once, and our extension method extending object, we may use it for all .NET types.

C#
public static class MyExtensions
{
    public static T CloneObject<T>(this object source)
    {
        T result = Activator.CreateInstance<T>();

        //// **** made things

        return result;
    }
}

Call:

C#
Customer Customer2 = customer1.CloneObject();

We can use the extension method in conjunction with ICloneable:

C#
public class Customer : ICloneable
{
   // Properties ...

    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 in a different way, the references properties (classes) or values properties (structs):

  • Structs - Copy bit by bit the value of property
  • Class – Copy 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 it internally.

MemberWiseClone example:

C#
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 to develop
  • Very little code
  • Easy to understand
  • It copies any fields/properties types (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 are not to be copied, they are linked.
  • The clone method returns object, consequently we will have do casting each time we use it.

If we try a completely depth copy, we have to do manual assignments of all references properties:

C#
public virtual object Clone()
{
    var result = this.MemberwiseClone();

    // Manual assignments 

    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 objects copies. It makes a depth copies but forces 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.

For we don’t write this code in all clone classes, we will create an extension method:

C#
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:

C#
Customer customer2 = customer1.CloneObjectSerializable();

If you run this code, it throw SerializationException:

Image 3

To prevent these errors, we mark the class with Serialization Attribute:

C#
[Serializable]
public class Customer

Pros

  • Easy to develop
  • 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 aren’t necessarily applying boxing / unboxing

Cons

  • It needs to mark with special attribute
  • For your implementation, it needs more code and logic
  • Memory Leak (thanks to deverton bezerra)

This method can be used with ICloneable perfectly maintaining any of its virtues.

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Cecabank
Spain Spain
MVP C# Corner 2017

MAP Microsoft Active Professional 2014

MCPD - Designing and Developing Windows Applications .NET Framework 4
MCTS - Windows Applications Development .NET Framework 4
MCTS - Accessing Data Development .NET Framework 4
MCTS - WCF Development .NET Framework 4

Comments and Discussions

 
QuestionImplement cloning with a constructor, not a method Pin
Peter Huber SG16-Aug-17 5:43
mvaPeter Huber SG16-Aug-17 5:43 
AnswerRe: Implement cloning with a constructor, not a method Pin
Juan Francisco Morales Larios25-Aug-17 3:08
Juan Francisco Morales Larios25-Aug-17 3:08 
QuestionIt's no longer recommended to use ICloneable interface Pin
Peter Huber SG16-Aug-17 5:27
mvaPeter Huber SG16-Aug-17 5:27 
AnswerRe: It's no longer recommended to use ICloneable interface Pin
Juan Francisco Morales Larios24-Aug-17 22:46
Juan Francisco Morales Larios24-Aug-17 22:46 
Question"My blog" link Pin
Nelek11-Apr-17 9:09
protectorNelek11-Apr-17 9:09 
AnswerRe: "My blog" link Pin
Juan Francisco Morales Larios11-Apr-17 10:30
Juan Francisco Morales Larios11-Apr-17 10:30 
QuestionBinaryFormatter - Memory Leak Pin
Deverton Bezerra23-Jan-17 22:53
Deverton Bezerra23-Jan-17 22:53 
AnswerRe: BinaryFormatter - Memory Leak Pin
Juan Francisco Morales Larios8-Feb-17 11:16
Juan Francisco Morales Larios8-Feb-17 11:16 
GeneralInteresting Pin
naymyohaen15-Jan-17 1:48
naymyohaen15-Jan-17 1:48 
GeneralA simple reason why ICloneable<T> doesnot work! Pin
Master.Man19804-Jan-17 5:54
Master.Man19804-Jan-17 5:54 
GeneralRe: A simple reason why ICloneable<T> doesnot work! Pin
Juan Francisco Morales Larios5-Jan-17 2:41
Juan Francisco Morales Larios5-Jan-17 2:41 
QuestionExcellent work; it inspired me, many thanks Juan Pin
ChristianMayr12-Jan-17 7:50
ChristianMayr12-Jan-17 7:50 
QuestionInteresting! Pin
Frans Vander Meiren28-Dec-16 22:13
Frans Vander Meiren28-Dec-16 22:13 
Nice work, Juan!
QuestionWorks nice Pin
Member 1027179628-Dec-16 9:25
Member 1027179628-Dec-16 9:25 
AnswerRe: Works nice Pin
Juan Francisco Morales Larios28-Dec-16 10:25
Juan Francisco Morales Larios28-Dec-16 10:25 
QuestionFaster Approach Pin
Member 997430628-Dec-16 7:35
Member 997430628-Dec-16 7:35 
AnswerRe: Faster Approach Pin
Juan Francisco Morales Larios28-Dec-16 10:39
Juan Francisco Morales Larios28-Dec-16 10:39 
AnswerRe: Faster Approach Pin
Member 1304275812-Apr-17 20:44
professionalMember 1304275812-Apr-17 20:44 
GeneralRe: Faster Approach Pin
Juan Francisco Morales Larios12-Apr-17 21:10
Juan Francisco Morales Larios12-Apr-17 21:10 
GeneralRe: Faster Approach Pin
Member 1056055613-Apr-17 3:07
professionalMember 1056055613-Apr-17 3:07 
GeneralRe: Faster Approach Pin
Juan Francisco Morales Larios13-Apr-17 22:10
Juan Francisco Morales Larios13-Apr-17 22:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.