Code
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace System
{
public static class CloneHelper
{
private static T CreatePrototype<T>(T obj)
where T : class
{
if (obj == null)
throw new ArgumentNullException("obj");
var type = obj.GetType();
if (!type.IsArray)
return (T)Activator.CreateInstance(type);
var array = (Array)(object)obj;
var length = array.Length;
var eType = type.GetElementType();
return (T)(object)Array.CreateInstance(eType, length);
}
/// <summary>
/// This method uses reflection to copy all field values.
/// </summary>
public static T DeepClone<T>(this T obj)
where T : class
{
if (obj == null)
return null;
var newValue = CreatePrototype(obj);
CopyFields(obj, newValue, true);
return newValue;
}
/// <summary>
/// This method uses reflection to copy all field values.
/// </summary>
public static T ShallowClone<T>(this T obj)
where T : class
{
if (obj == null)
return null;
var newValue = CreatePrototype(obj);
CopyFields(obj, newValue, false);
return newValue;
}
/// <summary>
/// <para>This method uses reflection to copy all field values.</para>
/// <para>Remark: only support SZ array, other array types are not supported.</para>
/// </summary>
public static void CopyFields<T>(T source, T dest, bool deepCopy)
where T : class
{
if (source == null || dest == null)
throw new ArgumentNullException();
var type = source.GetType();
if (type != dest.GetType())
throw new ArgumentException("source and dest is not the same type.");
if (type.IsArray)
{
CopyArray((Array)(object)source, (Array)(object)dest, type.GetElementType(), deepCopy);
}
else
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) as IEnumerable<FieldInfo>;
while (type.BaseType != typeof(object))
{
type = type.BaseType;
fields = fields.Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
}
foreach (var field in fields)
CopyField(source, dest, field, deepCopy);
}
}
private static void CopyArray(Array source, Array dest, Type elementType, bool deepCopy)
{
var length = source.Length;
if (length != dest.Length)
throw new ArgumentOutOfRangeException("dest", "Array source and dest don't have the same size.");
for (var i = 0; i < length; i++)
{
var oldValue = source.GetValue(i);
if (!deepCopy || oldValue == null || elementType.IsValueType || elementType == typeof(string))
dest.SetValue(oldValue, i);
else
dest.SetValue(oldValue.DeepClone(), i);
}
}
private static void CopyField<T>(T source, T dest, FieldInfo field, bool deepCopy)
{
var oldValue = field.GetValue(source);
var fieldType = field.FieldType;
if (!deepCopy || oldValue == null || fieldType.IsValueType || fieldType == typeof(string))
{
field.SetValue(dest, oldValue);
return;
}
var oldType = oldValue.GetType();
var newValue = CreatePrototype(oldValue);
var oldArray = oldValue as Array;
if (oldArray == null)
CopyFields(oldValue, newValue, deepCopy);
else
CopyArray(oldArray, (Array)newValue, oldType.GetElementType(), deepCopy);
field.SetValue(dest, newValue);
}
/// <summary>
/// This method uses reflection to copy all NON-INDEXED property values.
/// </summary>
public static void CopyProperties<T>(T source, T dest, bool deepCopy)
where T : class
{
if (source == null || dest == null)
throw new ArgumentNullException();
var type = source.GetType();
if (type != dest.GetType())
throw new ArgumentException("source and dest is not the same type.");
if (type.IsArray)
{
CopyArray((Array)(object)source, (Array)(object)dest, type.GetElementType(), deepCopy);
}
else
{
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
foreach (var property in properties)
if (property.CanRead && property.CanWrite)
CopyProperty(source, dest, property, deepCopy);
}
}
private static void CopyProperty<T>(T source, T dest, PropertyInfo property, bool deepCopy)
{
var oldValue = property.GetValue(source, null);
var fieldType = property.PropertyType;
if (!deepCopy || oldValue == null || fieldType.IsValueType || fieldType == typeof(string))
{
property.SetValue(dest, oldValue, null);
return;
}
var oldType = oldValue.GetType();
var newValue = CreatePrototype(oldValue);
var oldArray = oldValue as Array;
if (oldArray == null)
CopyFields(oldValue, newValue, deepCopy);
else
CopyArray(oldArray, (Array)newValue, oldType.GetElementType(), deepCopy);
property.SetValue(dest, newValue, null);
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace System
{
public static class CloneHelper
{
private static T CreatePrototype<T>(T obj)
where T : class
{
if (obj == null)
throw new ArgumentNullException("obj");
var type = obj.GetType();
if (!type.IsArray)
return (T)Activator.CreateInstance(type);
var array = (Array)(object)obj;
var length = array.Length;
var eType = type.GetElementType();
return (T)(object)Array.CreateInstance(eType, length);
}
/// <summary>
/// This method uses reflection to copy all field values.
/// </summary>
public static T DeepClone<T>(this T obj)
where T : class
{
if (obj == null)
return null;
var newValue = CreatePrototype(obj);
CopyFields(obj, newValue, true);
return newValue;
}
/// <summary>
/// This method uses reflection to copy all field values.
/// </summary>
public static T ShallowClone<T>(this T obj)
where T : class
{
if (obj == null)
return null;
var newValue = CreatePrototype(obj);
CopyFields(obj, newValue, false);
return newValue;
}
/// <summary>
/// <para>This method uses reflection to copy all field values.</para>
/// <para>Remark: only support SZ array, other array types are not supported.</para>
/// </summary>
public static void CopyFields<T>(T source, T dest, bool deepCopy)
where T : class
{
if (source == null || dest == null)
throw new ArgumentNullException();
var type = source.GetType();
if (type != dest.GetType())
throw new ArgumentException("source and dest is not the same type.");
if (type.IsArray)
{
CopyArray((Array)(object)source, (Array)(object)dest, type.GetElementType(), deepCopy);
}
else
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) as IEnumerable<FieldInfo>;
while (type.BaseType != typeof(object))
{
type = type.BaseType;
fields = fields.Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
}
foreach (var field in fields)
CopyField(source, dest, field, deepCopy);
}
}
private static void CopyArray(Array source, Array dest, Type elementType, bool deepCopy)
{
var length = source.Length;
if (length != dest.Length)
throw new ArgumentOutOfRangeException("dest", "Array source and dest don't have the same size.");
for (var i = 0; i < length; i++)
{
var oldValue = source.GetValue(i);
if (!deepCopy || oldValue == null || elementType.IsValueType || elementType == typeof(string))
dest.SetValue(oldValue, i);
else
dest.SetValue(oldValue.DeepClone(), i);
}
}
private static void CopyField<T>(T source, T dest, FieldInfo field, bool deepCopy)
{
var oldValue = field.GetValue(source);
var fieldType = field.FieldType;
if (!deepCopy || oldValue == null || fieldType.IsValueType || fieldType == typeof(string))
{
field.SetValue(dest, oldValue);
return;
}
var oldType = oldValue.GetType();
var newValue = CreatePrototype(oldValue);
var oldArray = oldValue as Array;
if (oldArray == null)
CopyFields(oldValue, newValue, deepCopy);
else
CopyArray(oldArray, (Array)newValue, oldType.GetElementType(), deepCopy);
field.SetValue(dest, newValue);
}
/// <summary>
/// This method uses reflection to copy all NON-INDEXED property values.
/// </summary>
public static void CopyProperties<T>(T source, T dest, bool deepCopy)
where T : class
{
if (source == null || dest == null)
throw new ArgumentNullException();
var type = source.GetType();
if (type != dest.GetType())
throw new ArgumentException("source and dest is not the same type.");
if (type.IsArray)
{
CopyArray((Array)(object)source, (Array)(object)dest, type.GetElementType(), deepCopy);
}
else
{
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
foreach (var property in properties)
if (property.CanRead && property.CanWrite)
CopyProperty(source, dest, property, deepCopy);
}
}
private static void CopyProperty<T>(T source, T dest, PropertyInfo property, bool deepCopy)
{
var oldValue = property.GetValue(source, null);
var fieldType = property.PropertyType;
if (!deepCopy || oldValue == null || fieldType.IsValueType || fieldType == typeof(string))
{
property.SetValue(dest, oldValue, null);
return;
}
var oldType = oldValue.GetType();
var newValue = CreatePrototype(oldValue);
var oldArray = oldValue as Array;
if (oldArray == null)
CopyFields(oldValue, newValue, deepCopy);
else
CopyArray(oldArray, (Array)newValue, oldType.GetElementType(), deepCopy);
property.SetValue(dest, newValue, null);
}
}
}