Given 2 objects A and B of type T, I want to assign the properties' values in A to the same properties in B without doing an explicit assignment for each property.
I want to save code like this:
b.Nombre = a.Nombre;
b.Descripcion = a.Descripcion;
b.Imagen = a.Imagen;
b.Activo = a.Activo;
doing something like
a.ApplyProperties(b);
Is it possible?
Because I believe Jon's version is a tad too complicated and and Steve's version is too simple, and I like Daniel's idea of an extension class.
Plus a Generic version is pretty but unnecessary as all items are objects.
I would like to volunteer my lean and mean version. Credits to all the above. :D
Code:
using System;
using System.Reflection;
/// <summary>
/// A static class for reflection type functions
/// </summary>
public static class Reflection
{
/// <summary>
/// Extension for 'Object' that copies the properties to a destination object.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public static void CopyProperties(this object source, object destination)
{
// If any this null throw an exception
if (source == null || destination == null)
throw new Exception("Source or/and Destination Objects are null");
// Getting the Types of the objects
Type typeDest = destination.GetType();
Type typeSrc = source.GetType();
// Iterate the Properties of the source instance and
// populate them from their desination counterparts
PropertyInfo[] srcProps = typeSrc.GetProperties();
foreach (PropertyInfo srcProp in srcProps)
{
if (!srcProp.CanRead)
{
continue;
}
PropertyInfo targetProperty = typeDest.GetProperty(srcProp.Name);
if (targetProperty == null)
{
continue;
}
if (!targetProperty.CanWrite)
{
continue;
}
if (targetProperty.GetSetMethod(true) != null && targetProperty.GetSetMethod(true).IsPrivate)
{
continue;
}
if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
{
continue;
}
if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType))
{
continue;
}
// Passed all tests, lets set the value
targetProperty.SetValue(destination, srcProp.GetValue(source, null), null);
}
}
}
Usage:
/// <summary>
/// ExampleCopyObject
/// </summary>
/// <returns></returns>
public object ExampleCopyObject()
{
object destObject = new object();
this.CopyProperties(destObject); // inside a class you want to copy from
Reflection.CopyProperties(this, destObject); // Same as above but directly calling the function
TestClass srcClass = new TestClass();
TestStruct destStruct = new TestStruct();
srcClass.CopyProperties(destStruct); // using the extension directly on a object
Reflection.CopyProperties(srcClass, destObject); // Same as above but directly calling the function
//so on and so forth.... your imagination is the limits :D
return srcClass;
}
public class TestClass
{
public string Blah { get; set; }
}
public struct TestStruct
{
public string Blah { get; set; }
}
As I was bored and a linq version was suggested by a comment
using System;
using System.Linq;
using System.Reflection;
/// <summary>
/// A static class for reflection type functions
/// </summary>
public static class Reflection
{
/// <summary>
/// Extension for 'Object' that copies the properties to a destination object.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public static void CopyProperties(this object source, object destination)
{
// If any this null throw an exception
if (source == null || destination == null)
throw new Exception("Source or/and Destination Objects are null");
// Getting the Types of the objects
Type typeDest = destination.GetType();
Type typeSrc = source.GetType();
// Collect all the valid properties to map
var results = from srcProp in typeSrc.GetProperties()
let targetProperty = typeDest.GetProperty(srcProp.Name)
where srcProp.CanRead
&& targetProperty != null
&& (targetProperty.GetSetMethod(true) != null && !targetProperty.GetSetMethod(true).IsPrivate)
&& (targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) == 0
&& targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType)
select new { sourceProperty = srcProp, targetProperty = targetProperty };
//map the properties
foreach (var props in results)
{
props.targetProperty.SetValue(destination, props.sourceProperty.GetValue(source, null), null);
}
}
}