I am trying to deep copy a complex object
public class Team
{
public string Id { get; set; }
Driver driver{ get; set;}
Driver codriver{ get; set;}
}
public class Driver
{
Team parentTeam{ get; set;}
public string DriverId { get; set; }
}
var modifiedTeams = new List<Team>
{
new Team {Id = "T1", Driver = new Driver { ParentTeam = "T1", DriverId = "D2" }, Codriver = new Driver { ParentTeam = "T1", DriverId = "C1"} },
new Team {Id = "T2", Driver = new Driver { ParentTeam = "T2", DriverId = "D1"} }
};
I want to deep copy the modified lists. Below is the utility that I am using.
/// <summary>
/// Utility
/// </summary>
public static class DeepCopyUtility
{
private static string[] _excludedPropertyNames = null;
private static BindingFlags _memberAccess = (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
/// <summary>
/// Copies the data of one object to another. The target object gets properties of the first.
/// Any matching properties (by name) are written to the target.
/// </summary>
/// <param name="source">The source object to copy from</param>
/// <param name="target">The target object to copy to public</param>
/// <param name="propertyNames"> </param>
public static void DeepCopy<T>(T source, T target, string[] propertyNames = null)
{
if (source == null)
{
throw new ArgumentNullException("Object is null");
}
if (propertyNames != null)
{
_excludedPropertyNames = propertyNames;
}
CopyObjectData(source, target, new Dictionary<object, object>());
}
/// <summary>
/// Copies the data of one object to another. The target object gets properties of the first.
/// Any matching properties (by name) are written to the target.
/// </summary>
/// <param name="source">The source object to copy from</param>
/// <param name="target">The target object to copy to</param>
/// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param>
public static void CopyObjectData(object source, object target, Dictionary<object, object> cloned)
{
Type type = source.GetType();
if (target == null && type.IsValueType == false && type != typeof(string))
{
if (source.GetType().IsArray)
{
target = Activator.CreateInstance(source.GetType().GetElementType());
}
else if (source.GetType().IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
if (typeof(IList).IsAssignableFrom(type))
{
target = (IList)Activator.CreateInstance(type);
}
else if (type.IsGenericType)
{
var objectType = type.GetGenericArguments().Single();
if (typeof(IList<>).MakeGenericType(objectType).IsAssignableFrom(type) || typeof(ISet<>).MakeGenericType(objectType).IsAssignableFrom(type))
{
target = Activator.CreateInstance(type);
}
}
}
else
{
target = Activator.CreateInstance(source.GetType());
}
}
MemberInfo[] miT = target.GetType().GetMembers(_memberAccess);
foreach (MemberInfo field in miT)
{
string name = field.Name;
// Skip over excluded properties
if (_excludedPropertyNames != null && _excludedPropertyNames.Contains(name))
{
continue;
}
object clone;
if (cloned.TryGetValue(source, out clone))
{
// this object has been cloned earlier, return reference to that clone
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);
cloned[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)
{
if (sourceField.PropertyType.IsArray && piTarget.PropertyType.IsArray)
{
CopyArray(source, target, piTarget, sourceField, cloned);
}
else if ((sourceField.PropertyType.IsGenericType && sourceField.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
&& (piTarget.PropertyType.IsGenericType && piTarget.PropertyType.GetGenericTypeDefinition() == typeof(List<>)))
{
CopyList(source, target, piTarget, sourceField, cloned);
}
else
{
CopySingleData(source, target, piTarget, sourceField, cloned);
}
}
}
}
}
private static void CopySingleData(object source, object target, PropertyInfo piTarget, PropertyInfo sourceField, Dictionary<object, object> cloned)
{
object sourceValue = sourceField.GetValue(source, null);
object targetValue = piTarget.GetValue(target, null);
if (sourceValue == null) { return; }
//instantiate target if needed
if (targetValue == null && piTarget.PropertyType.IsValueType == false && piTarget.PropertyType != typeof(string))
{
if (piTarget.PropertyType.IsArray)
{
targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
}
else
{
targetValue = Activator.CreateInstance(piTarget.PropertyType);
}
}
if (piTarget.PropertyType.IsValueType == false && piTarget.PropertyType != typeof(string))
{
CopyObjectData(sourceValue, targetValue, cloned);
piTarget.SetValue(target, targetValue, null);
}
else
{
if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName)
{
object tempSourceValue = sourceField.GetValue(source, null);
piTarget.SetValue(target, tempSourceValue, null);
cloned[target] = tempSourceValue;
}
else
{
CopyObjectData(piTarget, target, cloned);
}
}
}
private static void CopyArray(object source, object target, PropertyInfo piTarget, PropertyInfo sourceField, Dictionary<object, object> cloned)
{
object sourceValue = sourceField.GetValue(source, null);
if (sourceValue == null) { return; }
int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null);
Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength);
Array array = (Array)sourceField.GetValue(source, null);
for (int i = 0; i < array.Length; i++)
{
object o = array.GetValue(i);
object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
CopyObjectData(o, tempTarget, cloned);
targetArray.SetValue(tempTarget, i);
}
piTarget.SetValue(target, targetArray, null);
cloned[target] = targetArray;
}
private static void CopyList(object source, object target, PropertyInfo piTarget, PropertyInfo sourceField, Dictionary<object, object> cloned)
{
var sourceValue = ((IEnumerable)sourceField.GetValue(source, null)).Cast<object>().ToList();
if (!sourceValue.Any()) { return; }
int sourceLength = (int)sourceValue.GetType().GetProperty("Count").GetValue(sourceValue);
var listType = typeof(List<>);
Type[] genericArgs = sourceField.PropertyType.GetGenericArguments();
var concreteType = listType.MakeGenericType(genericArgs);
var newList = (IList)Activator.CreateInstance(concreteType);
var obj = (IList)sourceField.GetValue(source, null);
for (int i = 0; i < sourceLength; i++)
{
object[] ind = { i };
object o = obj[i];
object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetGenericArguments()[0]);
CopyObjectData(o, tempTarget, cloned);
newList.Insert(i, tempTarget);
}
piTarget.SetValue(target, newList, null);
cloned[target] = newList;
}
On execution I am getting "System.Reflection.TargetParameterCountException : Parameter count mismatch.". This is mainly because it is trying to get Team value from a list of teams. Can someone help me with how I could fix this.
Note: This utility code is referred from below links:- http://ift.tt/2AWKJYw
http://ift.tt/2yThvZj