/// <summary>
/// Copy each field in the <paramref name="source" /> to the matching field in the <paramref name="destination" />.
/// then
/// Copy each property in the <paramref name="source" /> to the matching property in the
/// <paramref name="destination" />.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Boolean DeepClone< TSource >( this TSource source, TSource destination ) {
if ( ReferenceEquals( source, destination ) ) {
return false;
}
if ( Equals( source, default( TSource ) ) ) {
return false;
}
if ( Equals( destination, default( TSource ) ) ) {
return false;
}
//copy all settable fields
// then
//copy all settable properties (going on the assumption that properties are the ones modifiying their private fields).
return CopyFields( source: source, destination: destination ) && CopyProperties( source: source, destination: destination );
}
/// <summary>
/// Copy the value of each field of the <paramref name="source" /> to the matching field in the
/// <paramref
/// name="destination" />
/// .
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Boolean CopyFields< TSource >( this TSource source, TSource destination ) {
try {
var sourceFields = source.GetType().GetAllFields();
var destFields = destination.GetType().GetAllFields();
foreach ( var field in sourceFields.Where( destFields.Contains ) ) {
CopyField( source: source, destination: destination, field: field );
}
return true;
}
catch ( Exception ) {
return false;
}
}
/// <summary>
/// Enumerate all fields of the <paramref name="type" />
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable< FieldInfo > GetAllFields( this Type type ) {
if ( null == type ) {
return Enumerable.Empty< FieldInfo >();
}
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
return type.GetFields( flags ).Union( GetAllFields( type.BaseType ) );
}
public static void CopyField< TSource >( this TSource source, TSource destination, [NotNull] FieldInfo field, Boolean mergeDictionaries = true ) {
if ( field == null ) {
throw new ArgumentNullException( "field" );
}
try {
var sourceValue = field.GetValue( source );
if ( mergeDictionaries ) {
var sourceAsDictionary = sourceValue as IDictionary;
if ( null == sourceAsDictionary ) {
return;
}
var destAsDictionary = field.GetValue( destination ) as IDictionary;
if ( null == destAsDictionary ) {
return;
}
foreach ( var key in sourceAsDictionary.Keys ) {
try {
destAsDictionary[ key ] = sourceAsDictionary[ key ];
}
catch ( Exception exception ) {
exception.Log();
}
}
return;
}
field.SetValue( destination, sourceValue );
}
catch ( TargetException exception ) {
exception.Log();
}
catch ( NotSupportedException exception ) {
exception.Log();
}
catch ( FieldAccessException exception ) {
exception.Log();
}
catch ( ArgumentException exception ) {
exception.Log();
}
}
/// <summary>
/// Copy the value of each get property of the <paramref name="source" /> to each set property of the
/// <paramref
/// name="destination" />
/// .
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Boolean CopyProperties< TSource >( this TSource source, TSource destination ) {
try {
var sourceProps = source.GetType().GetAllProperties().Where( prop => prop.CanRead );
var destProps = destination.GetType().GetAllProperties().Where( prop => prop.CanWrite );
foreach ( var prop in sourceProps.Where( destProps.Contains ) ) {
CopyProperty( source: source, destination: destination, prop: prop );
}
return true;
}
catch ( Exception ) {
return false;
}
}
/// <summary>
/// Enumerate all properties of the <paramref name="type" />
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable< PropertyInfo > GetAllProperties( this Type type ) {
if ( null == type ) {
return Enumerable.Empty< PropertyInfo >();
}
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
return type.GetProperties( flags ).Union( GetAllProperties( type.BaseType ) );
}
public static void CopyProperty< TSource >( this TSource source, TSource destination, PropertyInfo prop ) {
try {
var sourceValue = prop.GetValue( source, null );
prop.SetValue( destination, sourceValue, null );
}
catch ( TargetException exception ) {
exception.Log();
}
catch ( NotSupportedException exception ) {
exception.Log();
}
catch ( FieldAccessException exception ) {
exception.Log();
}
catch ( ArgumentException exception ) {
exception.Log();
}
}