Kavya Shetty

Kavya Shetty

  • 1.8k
  • 2
  • 2.8k

Deep Copy a complex object in C#

Nov 17 2017 4:31 AM
Hi,
 
I am trying to deep copy a complex object. Below is code for same.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Reflection;  
  6. namespace DDKOnline.Common  
  7. {  
  8. /// <summary>  
  9. /// Utility  
  10. /// </summary>  
  11. public static class DeepCopyUtility  
  12. {  
  13. /// <summary>  
  14. /// Copies the data of one object to another. The target object gets properties of the first.  
  15. /// Any matching properties (by name) are written to the target.  
  16. /// </summary>  
  17. ///  
  18. The source object to copy from///  
  19. The target object to copy topublic static void CopyObjectData(object source, object target)  
  20. {  
  21. CopyObjectData(source, target, String.Empty, BindingFlags.Public | BindingFlags.Instance);  
  22. }  
  23. /// <summary>  
  24. /// Copies the data of one object to another. The target object gets properties of the first.  
  25. /// Any matching properties (by name) are written to the target.  
  26. /// </summary>  
  27. ///  
  28. The source object to copy from///  
  29. The target object to copy to///  
  30. A comma delimited list of properties that should not be copied///  
  31. Reflection binding accesspublic static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess)  
  32. {  
  33. string[] excluded = null;  
  34. if (!string.IsNullOrEmpty(excludedProperties))  
  35. {  
  36. excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);  
  37. }  
  38. MemberInfo[] miT = target.GetType().GetMembers(memberAccess);  
  39. foreach (MemberInfo Field in miT)  
  40. {  
  41. string name = Field.Name;  
  42. // Skip over excluded properties  
  43. if (string.IsNullOrEmpty(excludedProperties) == false  
  44. && excluded.Contains(name))  
  45. {  
  46. continue;  
  47. }  
  48. if (Field.MemberType == MemberTypes.Field)  
  49. {  
  50. FieldInfo sourcefield = source.GetType().GetField(name);  
  51. if (sourcefield == null) { continue; }  
  52. object SourceValue = sourcefield.GetValue(source);  
  53. ((FieldInfo)Field).SetValue(target, SourceValue);  
  54. }  
  55. else if (Field.MemberType == MemberTypes.Property)  
  56. {  
  57. PropertyInfo piTarget = Field as PropertyInfo;  
  58. PropertyInfo sourceField = source.GetType().GetProperty(name, memberAccess);  
  59. if (sourceField == null) { continue; }  
  60. if (piTarget.CanWrite && sourceField.CanRead)  
  61. {  
  62. object targetValue = piTarget.GetValue(target, null);  
  63. object sourceValue = sourceField.GetValue(source, null);  
  64. if (sourceValue == null) { continue; }  
  65. if (sourceField.PropertyType.IsArray  
  66. && piTarget.PropertyType.IsArray  
  67. && sourceValue != null)  
  68. {  
  69. CopyArray(source, target, memberAccess, piTarget, sourceField, sourceValue);  
  70. }  
  71. else  
  72. {  
  73. CopySingleData(source, target, memberAccess, piTarget, sourceField, targetValue, sourceValue);  
  74. }  
  75. }  
  76. }  
  77. }  
  78. }  
  79. private static void CopySingleData(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object targetValue, object sourceValue)  
  80. {  
  81. //instantiate target if needed  
  82. if (targetValue == null  
  83. && piTarget.PropertyType.IsValueType == false  
  84. && piTarget.PropertyType != typeof(string))  
  85. {  
  86. if (piTarget.PropertyType.IsArray)  
  87. {  
  88. targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType());  
  89. }  
  90. else  
  91. {  
  92. targetValue = Activator.CreateInstance(piTarget.PropertyType);  
  93. }  
  94. }  
  95. if (piTarget.PropertyType.IsValueType == false  
  96. && piTarget.PropertyType != typeof(string))  
  97. {  
  98. CopyObjectData(sourceValue, targetValue, "", memberAccess);  
  99. piTarget.SetValue(target, targetValue, null);  
  100. }  
  101. else  
  102. {  
  103. if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName)  
  104. {  
  105. object tempSourceValue = sourceField.GetValue(source, null);  
  106. piTarget.SetValue(target, tempSourceValue, null);  
  107. }  
  108. else  
  109. {  
  110. CopyObjectData(piTarget, target, "", memberAccess);  
  111. }  
  112. }  
  113. }  
  114. private static void CopyArray(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object sourceValue)  
  115. {  
  116. int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null);  
  117. Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength);  
  118. Array array = (Array)sourceField.GetValue(source, null);  
  119. for (int i = 0; i < array.Length; i++)  
  120. {  
  121. object o = array.GetValue(i);  
  122. object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType());  
  123. CopyObjectData(o, tempTarget, "", memberAccess);  
  124. targetArray.SetValue(tempTarget, i);  
  125. }  
  126. piTarget.SetValue(target, targetArray, null);  
  127. }  
  128. }  
  129. }  
  130. I want to add list copy also to this code something on below lines.  
  131. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))  
  132. {  
  133. if (typeof(IList).IsAssignableFrom(type))  
  134. {  
  135. var collection = (IList)Activator.CreateInstance(type);  
  136. cloned[source] = collection;  
  137.   
  138. foreach (var element in source as IEnumerable)  
  139. {  
  140. collection.Add(CloneProcedure(element, cloned));  
  141. }  
  142. return collection;  
  143. }  
  144. else if (type.IsGenericType)  
  145. {  
  146. var objectType = type.GetGenericArguments().Single();  
  147. if (typeof(IList<>).MakeGenericType(objectType).IsAssignableFrom(type) ||  
  148. typeof(ISet<>).MakeGenericType(objectType).IsAssignableFrom(type))  
  149. {  
  150. var collection = Activator.CreateInstance(type);  
  151. cloned[source] = collection;  
  152.   
  153. var addMethod = collection.GetType().GetMethod("Add");  
  154. foreach (var element in source as IEnumerable)  
  155. {  
  156. addMethod.Invoke(collection, new[] { CloneProcedure(element, cloned) });  
  157. }  
  158. return collection;  
  159. }  
  160. }  
  161. return source;  
  162. }  
But each time I get "Parameter out of bounds" can someone help me with this.
 
Reference:
 
https://ddkonline.blogspot.com/2010/04/net-deep-copy-between-2-different.html?_sm_au_=iVV8TZZ5L71MRvZf
 
https://stackoverflow.com/a/2266441/4583547

Answers (1)