Sorry for the delay; here's my Extensions class for our simple object mapper. It's easier to use than AutoMapper, IMO.
I'll start with some examples of its usage:
(assuming all domain & model classes implement the IMappable interface):
// domain -> model
ModelClass model = domainObject.MapTo<ModelClass>();
// model -> domain
ModelClass model = domainObject.MapTo<ModelClass>();
// add extra properties
Address defaultAddress = model.MapTo<Address>(customer.BillingAddress);
// model -> domain; setting extra properties via lambda
ProductReview review = model.MapTo<ProductReview>(r =>
{
r.CustomerId = _workContext.CurrentCustomer.Id;
r.IsApproved = false;
r.CreatedOnUtc = DateTime.Now;
});
source code:
using System;
using Nop.Core.Infrastructure;
using Nop.Web.Framework.Mvc;
namespace Nop.Web.Framework
{
public interface IMappable
{
}
public static class MappingExtensions
{
/// <summary>
/// Get an object of type 'toType', created from the current object.
/// </summary>
/// <typeparam name="toType">The type to map to</typeparam>
/// <param name="from">The object to map from</param>
/// <returns>The mapped object</returns>
public static toType MapTo<toType>(this IMappable from) where toType : IMappable, new()
{
var newTo = new toType();
return (toType)from.MapRecursive(newTo);
}
/// <summary>
/// Get an object of type 'toType' created from the to object and replacings the properties matched in from.
/// This will also update the 'to' object's properties.
/// </summary>
/// <typeparam name="toType">The type to map to</typeparam>
/// <param name="from">The object to map from</param>
/// <param name="to">The object to use for mapping</param>
/// <returns>The mapped object</returns>
public static toType MapTo<toType>(this IMappable from, IMappable to) where toType : IMappable
{
return (toType)from.MapRecursive(to);
}
/// <summary>
/// Get an object of type 'toType' created from the to object and replacings the properties matched in from.
/// This will also update the 'to' object's properties.
/// </summary>
/// <typeparam name="toType">The type to map to</typeparam>
/// <param name="from">The object to map from</param>
/// <param name="to">The object to use for mapping</param>
/// <param name="initalizer">Action to invoke, to set extra properties upon the returned object</param>
/// <returns>The mapped object</returns>
public static toType MapTo<toType>(this IMappable from, IMappable to, Action<toType> initalizer) where toType : IMappable
{
var newTo = (toType)from.MapRecursive(to);
initalizer(newTo);
return newTo;
}
/// <summary>
/// Get an object of type 'toType' created from the current object and set properties on the return object in the action.
/// </summary>
/// <typeparam name="toType">The type to map to</typeparam>
/// <param name="from">The object to map from</param>
/// <param name="initalizer">Action to invoke, to set extra properties upon the returned object</param>
/// <returns>The mapped object</returns>
public static toType MapTo<toType>(this IMappable from, Action<toType> initalizer) where toType : IMappable, new()
{
var newTo = new toType();
newTo = (toType)from.MapRecursive(newTo);
initalizer(newTo);
return newTo;
}
private static object MapRecursive(this object from, object newTo)
{
foreach (var toProp in newTo.GetType().GetProperties())
{
foreach (var fromProp in from.GetType().GetProperties())
{
if (fromProp.CanRead && toProp.CanWrite)
{
try
{
// Same name and type
if (fromProp.Name.ToLower() == toProp.Name.ToLower()
&& fromProp.PropertyType == toProp.PropertyType)
{
var fromValue = fromProp.GetValue(from);
toProp.SetValue(newTo, fromValue);
}
// Same name but to property is nullable
else if (fromProp.Name.ToLower() == toProp.Name.ToLower()
&& fromProp.GetValue(from).GetType().Namespace.StartsWith("System")
&& Nullable.GetUnderlyingType(toProp.PropertyType) != null)
{
Type underlying = Nullable.GetUnderlyingType(toProp.PropertyType);
object fromValue = Convert.ChangeType(fromProp.GetValue(from), underlying);
toProp.SetValue(newTo, fromValue);
}
// Same name but different system types
else if (fromProp.Name.ToLower() == toProp.Name.ToLower()
&& fromProp.GetValue(from).GetType().Namespace.StartsWith("System")
&& toProp.GetValue(newTo).GetType().Namespace.StartsWith("System"))
{
object fromValue = Convert.ChangeType(fromProp.GetValue(from), toProp.GetValue(newTo).GetType());
toProp.SetValue(newTo, fromValue);
}
// Same name but different complex types
else if (fromProp.Name.ToLower() == toProp.Name.ToLower())
{
toProp.SetValue(newTo, fromProp.GetValue(from).MapRecursive(toProp.GetValue(newTo)));
}
}
catch { }
}
}
}
return newTo;
}
}
}