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