Thursday, August 27, 2009

The Need for Cloning an Object

I am working on a project in XAF and came into the need of cloning an object but needed to exclude certain properties.  I looked into the CloneHelper but it didn’t do what I needed.  So I wrote a simple method to handle this requirement.  A few things to know, any properties that are readonly do not need to be included in the exclusion.  Also the Oid property (is readonly) does not need to be excluded.  So to get this working, copy the code:

public static T CloneObject<T>(T sourceObj, T destObj, params string[] excludeProperties)
{
// Get the properties of the Source Object
PropertyInfo[] propCollection = sourceObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (PropertyInfo pInfo in propCollection)
{
// Exclude any properties from the exclude list
if (Array.Find<string>(excludeProperties, val => val.Equals(pInfo.Name)) == null && !pInfo.IsDefined(typeof(NonCloneableAttribute), false))
{
PropertyInfo tmpProp = destObj.GetType().GetProperty(pInfo.Name);
if (tmpProp.CanWrite)
tmpProp.SetValue(destObj, pInfo.GetValue(sourceObj, null), null);
}
}

return destObj;
}


To use this method, simply create the object that will become the cloned object and pass the source like so:



public static MyClonedObject CloneLineItem(DevExpress.Xpo.Session session, MyClonedObject sourceLineItem, params string[] excludeProperties)
{
MyClonedObject clonedLineItem = new MyClonedObject(session);
return CloneObject<MyClonedObject>(sourceLineItem, clonedLineItem, excludeProperties);
}


Create a simple method like above and pass something like:



MyClonedObject clone = CloneLineItem(this.Session, this, "Parent", "Total", "Payments");


In this example the properties Payments, Total, and Parent will be ignored when cloned.  I could have also just called it without any exclusions like so:



MyClonedObject clone = CloneLineItem(this.Session, this);

If this helps you out let me know…


Updated: Added support for the NonCloneableAttribute attribute.



Happy Coding!!

3 comments:

Anonymous said...

Hi
I suggest you pay attention to the DevExpress.Persistent.Base.Cloner class. I suppose it helps you in your situation.

Gary Cox said...

Thanks for your reply, however looking at how much code is involved to accomplish something so simple I believe I will keep my method instead of using the Cloner class.

Gary Cox said...

One other item to keep in mind brought to my attention by Martin Praxmarer (Smart Man) that the method will not work if you have a collection. This method will skip over your collection and only clone the properties with setters. If you have a simple class and just want to clone it without the extra overhead of Cloner, then use this, otherwise if your class is more complex use the Cloner class.

 
Creative Commons License
Blogged Information and Code is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.