Click here to Skip to main content
15,867,141 members
Articles / Programming Languages / C#
Article

Generics and Cloning

Rate me:
Please Sign up or sign in to vote.
2.83/5 (12 votes)
12 Jun 2006CPOL3 min read 52.7K   262   23   7
How to clone generic/template objects
Sample Image - 0g_GenericsAndCloning.jpg

Introduction

In many applications, there is the need to track changes to the data presented to users. There are several approaches in achieving this. In this article, I cover an approach in which I use Cloning and Generics to be able to compare objects and determine if any changes have been made. The use of cloning is important because in some systems the instantiation of an object could be somewhat expensive. Cloning allows us to do a deep copy of the object already instantiated thus preventing the expensive process. Once the object is cloned, we can modify the cloned copy with the new information provided by the user and determine what changes have been made. In order to compare the objects, we need to override the Equals method from the Object class. The challenge with cloning is that we would like to know the object type and minimize the code sections required to do the cloning. In short, we would like to create a base class from which we can clone any object type. This is where Generics can help us.

Background

To better understand this article, I recommend that the readers be somewhat familiar with the following concepts:

  • Generics
  • Cloning/ICloneable

The code for this article was written using .NET 2.0.

Using the Code

The first step is to create the CloneBase class (CloneBase.cs) which implements the ICloneable interface. This is needed to create a copy of object. Any class that implements this interface should also have the XML attribute [Serializable]. Not adding this attribute causes an exception to occur. This attribute must also be added to all the classes that inherit from the base class we are now creating. This takes care of the cloning part of the equation. Now, we need to be able to support different types. In order to do that, we need to declare the class as a template/generic definition by adding the generic type parameter <T>.

C#
 [Serializable]
 public class CloneBase<T> : ICloneable 
 {
   public CloneBase() { } 
   ...  

The generic type parameter is needed because this is what is used to replace where the concrete type would be. In other words, when we need to return a clone of a certain type, T is replaced by such type. We will be able to see this with the implementation of the Clone method. Notice how this method has a return type of T.

C#
public T Clone()
{
      T clone = default(T);        //initialize to default not null
      try
      {
            BinaryFormatter bf = new BinaryFormatter();     //helper to serialize
            MemoryStream memStream = new MemoryStream();    
            bf.Serialize(memStream, this);
            memStream.Flush();
            memStream.Position = 0;
            clone = ((T)bf.Deserialize(memStream));  //this returns the copy of type T
      }
       catch (Exception ex)
      {
            m_status = ex.Message;
      }

       return clone;
}

This code serializes the object into a memory stream, which creates a copy of the object. It then deserializes the generic object by using the line of code below. We can notice the casting done using the generic type (T). The new object is then returned.

C#
clone = ((T)bf.Deserialize(memStream));   //this returns the copy of type T   

We can now take a look at the client code which uses this base class. The project associated with this article has a Product class (Product.cs), which is used to represent a generic product. The class inherits from the CloneBase base class. Notice how this class too must have the XML attribute [Serializable]. This class also overrides the Equals method from the Object class. This is done to implement our own object comparison logic. In this case, we are comparing the value of all the data members. If any of the values is not the same, the code returns false.

C#
[Serializable]
 class Product : CloneBase<Product>
 {
        //data members declared here

        public override bool Equals(object obj)
        {
            bool bRtn = true;

            if (obj != null)
            {
                Product objRef = (Product)obj;

                //simple object type comparison
                if (this.Name != objRef.Name ||  
			this.Description != objRef.Description ||
                    	this.Sku != objRef.Sku || this.Count != objRef.Count)
                    bRtn = false;
            }
            else
                bRtn = false;

            return bRtn;
        }
}

We can now take a look at Windows form created for this article. This simple form displays all the data values for a Product object. When pressing the Save button, the application creates a clone of the object, assigns the values from the form to the clone, and compares the original object with the clone.

C#
private void btnSave_Click(object sender, EventArgs e)
{
            Product clone = _prod.Clone();                //create clone

            if (clone != null)
            {
                UIValues(clone, false);            //get current UI values;
                
                //check to see if any changes
                if (_prod.Equals(clone) == true)
                    MessageBox.Show("There is no change", this.Text); 
                else
                    MessageBox.Show("There is a change", this.Text); 
            }
            else
            {
                //did not clone!!! Use status to check for errors
                MessageBox.Show(_prod.Status, this.Text); 
            }
}

Points of Interest

I have found the use of generics to be very useful. This was a great new feature of .NET 2.0. There are also many generic list classes which we can use to eliminate the use of classes like the ArrayList. I hope this article is useful to some of you. I look forward to getting your feedback.

History

  • 0g06012006: Initial version

License

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


Written By
Architect OG-BITechnologies
United States United States
Software engineer, author & speaker who enjoys mentoring, learning, speaking and sharing with others about software development technologies. Microsoft MVP.

My Blog

Comments and Discussions

 
GeneralMy vote of 5 Pin
ozkary16-Feb-11 7:31
ozkary16-Feb-11 7:31 
GeneralUnusual approach... Pin
Pete Appleton19-Jun-06 22:32
Pete Appleton19-Jun-06 22:32 
AnswerRe: Unusual approach... Pin
ozkary20-Jun-06 8:14
ozkary20-Jun-06 8:14 
Not too unusual for complex systems.

yes, cloning is inefficient, but the approach here is for those cases when cloning is more efficient than creating a new instance of the object. In this example, the class I used is quite simple, but for a more complex system there could be instances when the initialization is more expensive than cloning.

MemberWiseClone would not work when you need to clone a reference type. In this example, the class is very simple, but what if the class has reference types as data members? A deep copy is needed when using reference types.

Method Signature:

The signature of a method is the combination of the method's name along with the number and types of the parameters (and their order).

thanks for the feedback.
GeneralRe: Unusual approach... Pin
Pete Appleton20-Jun-06 23:03
Pete Appleton20-Jun-06 23:03 
GeneralNo need for a base class [modified] Pin
User 20688512-Jun-06 12:31
User 20688512-Jun-06 12:31 
GeneralDownload file and image not accessible... Pin
Jun Du12-Jun-06 10:10
Jun Du12-Jun-06 10:10 
GeneralRe: Download file and image not accessible... Pin
ozkary12-Jun-06 10:30
ozkary12-Jun-06 10:30 

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.