Home > .NET, C# > C# Object Cloning Machinery

C# Object Cloning Machinery

March 16th, 2009 Leave a comment Go to comments

Introduction

In most cases, no matter what area of software development you are involved in, you will need a functionality of cloning your objects. The .NET Framework provides you 3 ways of achieving your object copying goal:

  1. Implement the ICloneable interface, and develop cloning functionality manually for each class involved in your desired cloning.
  2. Serialize you object to binary stream and deserialize it utilizing BinaryFormatter and MemoryStream classes. In this case your classes will need to be Serializable.
  3. Clone using Reflections.

Sometimes, when you are working on a large project, a “stupid” deep copying would not be sufficient. Let’s say, in some cases you need to include sub-objects, and in some of them not. For example, lets consider these classes

public class Person
{
    private List<Person> _friends = new List<Person>();

    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public List<Person> Friends { get { return _friends; } }
    public PersonManager Manager { get; set; }
}

public class PersonManager
{
    private List<Person> _persons = new List<Person>();
    List<Person> Persons
    {
        get { return _persons; }
    }
}

In some cases, when copying a single Person there is no need to copy the PersonManager too. In other cases you would like to include Person’s Friends in cloning, and again, in others don’t. As you have already noticed, there are too many cases in this trivial example. In real situation they will be much more complicated.

Solution

I suggest a declarative way of defining the cloning logic. Consider the following modification to our Person class:

public class Person
{
    private List<Person> _friends = new List<Person>();

    public string Firstname { get; set; }
    public string Lastname { get; set; }

    [Cloneable(CloneableState.Exclude)]
    [Cloneable(CloneableState.Include, "Friends")]
    public List<Person> Friends { get { return _friends; } }

    [Cloneable(CloneableState.Exclude)]
    public PersonManager Manager { get; set; }
}

It says that, when cloning the Person class, exclude Manager and Friends objects from cloning. However, when cloning with “Friends” flavor ([Cloneable(CloneableState.Include, "Friends")]), copy Person’s friends either. The usage of this machinery is quite easy. Example:

Person clone = (Person)ObjectCloner.Clone(person);
Person cloneWithFriends = (Person)ObjectCloner.Clone(person, "Friends");

So, the first statement in previous sample copies only Firstname and Lastname. The second one performs deep copy and clones person’s friends too.

Here is the output of the demo application which is based on the sample described earlier.

Object Cloner Demo

Here you can see, that both copies of “De Niro” have no manager defined, and when cloning with “Friends” flavor, machinery performs deep copy by filling person’s friends.

Downloads

Attached Files:

  1. avatar
    vazoffsky
    May 25th, 2009 at 03:28 | #1

    hey there mate :)
    just a suggestion. what if I want to ‘clone’ the references?
    in your example it would be very much appropriate to clone the
    person itself and lets say copy the references to his friends (without creating new instances of each friend). Please correct me if I am wrong, I might not have a ‘deep’ understanding of how the ‘deep copy’ works :)
    so please )))

  2. avatar
    rubenhakopian
    June 2nd, 2009 at 02:30 | #2

    hey, it might be a really useful scenario. I will add it on the top of my ToDo list! The only drawback I see now, is that this feature will complicate the utility. It might be hard to determine if resulting clonned object is really cloned or just reference copied. Anyway, thanks for nice suggestion though.

    Take care!

  3. June 4th, 2009 at 20:59 | #3

    Hi, good post. I have been woondering about this issue,so thanks for posting. I’ll definitely be coming back to your site.

  1. No trackbacks yet.