In many applications it’s necessary to copy data between objects. Especially these days where we often have entities and Data Transfer Objects (DTO) where data needs to be shuttled back and forth between two objects I find it handy to have a simple routine that performs at least rudimentary, shallow data copying for me without manually having to write data mapping code at least if the properties identically or nearly identically. A few days ago I had a lengthy discussion about this topic on Twitter as well and some suggestions that some sort of data copying mechanism should be built into the .NET framework.
Now there are a number of ways to ‘copy’ .NET objects. You can clone instances using the .Clone() method and there are various serialization/deserialization techniques that can be used. There’s also a very nice library called Automapper from Jimmy Bogard, that provides a declarative way to map/copy objects although you have to explicitly pre-declare your object types to be mapped the advantage of which is that most of the Reflection overhead is incurred only once. But this doesn’t always address the issue in a lot of application level scenarios. All these approaches create a new instance of an object rather than copying data into an existing instance. Also in a lot of situations I don’t actually want to copy two objects of the same type – take the Entity-> DTO object example: These two objects are of different types yet they have many (or often all) of the same properties that match 1-1 and need to be copied.
I’ve had a simple object copying routine in my base tool library for some years that performs shallow object copies by matching property/field names. It’s neither fancy nor very efficient as it uses Reflection, but it works well for many scenarios:
/// <summary>
/// Copies the data of one object to another. The target object 'pulls' properties of the first.
/// This any matching properties are written to the target.
///
/// The object copy is a shallow copy only. Any nested types will be copied as
/// whole values rather than individual property assignments (ie. via assignment)
/// </summary>
/// <param name="source">The source object to copy from</param>
/// <param name="target">The object to copy to</param>
/// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param>
/// <param name="memberAccess">Reflection binding access</param>
public static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess)
{
string[] excluded = null;
if (!string.IsNullOrEmpty(excludedProperties))
excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
foreach (MemberInfo Field in miT)
{
string name = Field.Name;
// Skip over any property exceptions
if (!string.IsNullOrEmpty(excludedProperties) &&
excluded.Contains(name))
continue;
if (Field.MemberType == MemberTypes.Field)
{
FieldInfo SourceField = source.GetType().GetField(name);
if (SourceField == null)
continue;
object SourceValue = SourceField.GetValue(source);
((FieldInfo)Field).SetValue(target, SourceValue);
}
else if (Field.MemberType == MemberTypes.Property)
{
PropertyInfo piTarget = Field as PropertyInfo;
PropertyInfo SourceField = source.GetType().GetProperty(name, memberAccess);
if (SourceField == null)
continue;
if (piTarget.CanWrite && SourceField.CanRead)
{
object SourceValue = SourceField.GetValue(source, null);
piTarget.SetValue(target, SourceValue, null);
}
}
}
}
As you can see this is a pretty simplistic approach to copying – it uses Reflection to iterate over the target object and tries to read the properties on the source object. Matching property names are then read and assigned on the target object. If types don’t line up the routine will fail. You can explicitly give a list of properties that are to be excluded from updates. For entity updates this will usually be auto-generated fields like Pks and time stamps that should be skipped.
There are a few issues with this approach. The biggest is that it uses Reflection so it has a bit of overhead walking the two objects and and looking up fields. Using the most restrictive BindingFlags filter helps some but Reflection is relatively slow. Of course it depends on the scenario you are using this for. The other issue has to do with failure tracking – if property copies fail for whatever reason you may end up with an object that is in an invalid state as some properties may have already copied while others have not.
Copies are only shallow meaning only a single level is copied. Any nested objects are copied as full instances rather than walking through each individual child object (which gets very complicated quickly having to deal with object recursion, and various list types etc.).
I’ve had good luck with this routine in various applications, especially in service or callback scenarios where inbound parameter data has to be copied back to business entities. For example, here’s a REST API call in an ASP.NET MVC application that receives an XML or JSON raw post buffer that is deserialized and then inserted into the database:
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Put)]
public ActionResult PostNewCodeSnippetObject()
{
StreamReader sr = new StreamReader(Request.InputStream);
string data = sr.ReadToEnd();
sr.Close();
Snippet inputSnippet = null;
if (Request.ContentType == "text/javascript" || Request.ContentType == "application/json")
{
JSONSerializer ser = new JSONSerializer(SupportedJsonParserTypes.WestWindJsonSerializer);
inputSnippet = ser.Deserialize(data, typeof(Snippet)) as Snippet;
}
else if (Request.ContentType == "text/xml")
{
inputSnippet = SerializationUtils.DeSerializeObject(data, typeof(Snippet)) as Snippet;
}
else
return ExceptionResult("Unsuppported data input format. Please provide input content-type as text/javascript, application/json or text/xml.");
busCodeSnippet codeSnippet = new busCodeSnippet();
codeSnippet.NewEntity();
DataUtils.CopyObjectData(inputSnippet, codeSnippet.Entity, "Id", BindingFlags.Public | BindingFlags.Instance);
if (!codeSnippet.Validate())
return this.ExceptionResult("Code snippet validation failed: " + codeSnippet.ValidationErrors.ToString());
if (!codeSnippet.Save())
return this.ExceptionResult("Couldn't save new code snippet: " + codeSnippet.ValidationErrors.ToString());
return ApiResult(codeSnippet.Entity);
}
In this case there are 15 properties copies and it sure beats writing out those 15 properties by hand and updating them as the structures change. Having a generic object copying routine reduces the amount of code as well as making maintenance easier as you don’t have to back fit object structure changes into the code.
Note that this example works with 2 objects of differing types: one is the input DTO, while the other is the business entity. Plain clone and serialization routines native in .NET don’t address this scenario because of the type differences. Automapper would potentially address this scenario but it can’t copy into an existing entity – here I need to have a new entity that generates a new PK and a couple of other defaults – creating a new instance wouldn’t be able to get those default values. This issue is more pronounced in some scenarios like LINQ to SQL Entities needing to be update.
Copying in the Runtime?
It would be nice if this sort of functionality was native to the .NET runtimes. This is such a common scenario IMHO, and I’ve seen tons of questions surrounding this topic (and one of them sparked the initial conversation again in Twitter last week). Internally the .NET framework could maybe get away with some direct property mapping for same types so there would be no need to reflect over fields/properties. For differing types Reflection (or as Automapper does – load based mapping) is probably unavoidable, but in many scenarios the performance reqiurements aren’t that critical since we’re usually talking about updates which tend to be much less frequent than reads in most applications. The other reason this should be in the runtime is that it’s a hideously complex process if done right (ie. deep copies) where you could specify object nesting levels and recursion behavior.
I’m not holding my breath. But I’d be interested if others are finding this functionality something they common use or wish they could use in a standard way.
Other Posts you might also like