diff Source/Mapping/ExpressionMapper.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Mapping/ExpressionMapper.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,785 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+
+using BLToolkit.Common;
+using BLToolkit.Data.Linq;
+using BLToolkit.Reflection;
+
+using JetBrains.Annotations;
+
+namespace BLToolkit.Mapping
+{
+	class Mapper<TS,TD>
+	{
+		public Func<TS,MappingContext,TD> Map;
+	}
+
+	class MappingContext
+	{
+		public Dictionary<object,object> Objects;
+		public Func<object,object>       GetParent;
+		public List<Action<object>>      CrossActions;
+		public Dictionary<object,List<Action<object,object>>> Crosses;
+	}
+
+	class MappingParameters
+	{
+		public   MappingSchema             MappingSchema;
+		public   bool                      DeepCopy              = true;
+		public   bool                      HandleCrossReferences = true;
+		public   bool                      IncludeComplexMapping;
+
+		public   Dictionary<object,object> MapperList     = new Dictionary<object,object>();
+
+		public   bool                      UseContext;
+		public   bool                      ContextParameterUsed;
+
+		readonly ParameterExpression      _mappingContext = Expression.Parameter(typeof(MappingContext), "ctx");
+		public   ParameterExpression       MappingContext
+		{
+			get
+			{
+				ContextParameterUsed = true;
+				return _mappingContext;
+			}
+		}
+	}
+
+	public class ExpressionMapper<TSource,TDest>
+	{
+		readonly MappingParameters     _parameters;
+		private  Func<object,object>   _getCurrent;
+		private  Action<object,object> _setCurrent;
+
+		public bool DeepCopy              { get { return _parameters.DeepCopy;              } set { _parameters.DeepCopy              = value; } }
+		public bool HandleBackReferences  { get { return _parameters.HandleCrossReferences; } set { _parameters.HandleCrossReferences = value; } }
+		public bool IncludeComplexMapping { get { return _parameters.IncludeComplexMapping; } set { _parameters.IncludeComplexMapping = value; } }
+
+		public ExpressionMapper()
+			: this(Map.DefaultSchema)
+		{
+		}
+
+		public ExpressionMapper(MappingSchema mappingSchema)
+		{
+			_parameters = new MappingParameters { MappingSchema = mappingSchema };
+		}
+
+		ExpressionMapper(MappingParameters parameters)
+		{
+			_parameters = parameters;
+		}
+
+		#region Value Converter
+
+		interface IValueConvertHelper
+		{
+			Expression GetConverter   (Expression source);
+			Expression CheckNull      (ExpressionMapper<TSource,TDest> mapper, Expression source, object nullValue, MapValue[] mapValues, object defaultValue, MapValue[] srcMapValues);
+			Expression SourceMapValues(ExpressionMapper<TSource,TDest> mapper, Expression source, object nullValue, object defaultValue, MapValue[] srcMapValues);
+			Expression DestMapValues  (ExpressionMapper<TSource,TDest> mapper, Expression source, object nullValue, MapValue[] mapValues, object defaultValue);
+		}
+
+		class ValueConvertHelper<TS,TD> : IValueConvertHelper
+		{
+			public Expression GetConverter(Expression source)
+			{
+				return Expression.Invoke(Expression.Constant(Convert<TD,TS>.From), source);
+			}
+
+			public Expression CheckNull(
+				ExpressionMapper<TSource,TDest> mapper,
+				Expression                      source,
+				object                          nullValue,
+				MapValue[]                      mapValues,
+				object                          defaultValue,
+				MapValue[]                      srcMapValues)
+			{
+				var param =
+					source.NodeType != ExpressionType.MemberAccess &&
+					source.NodeType != ExpressionType.Parameter    &&
+					source.NodeType != ExpressionType.Constant?
+						Expression.Parameter(typeof(TS), "p") :
+						null;
+
+				var nexpr = Expression.Constant(nullValue ?? default(TD));
+
+				var expr =
+					source.NodeType == ExpressionType.Constant && ((ConstantExpression)source).Value == null ?
+						nexpr as Expression:
+						Expression.Condition(
+							Expression.Equal(param ?? source, Expression.Constant(null)),
+							nexpr.Value == null ? Expression.Convert(nexpr, typeof(TD)) : nexpr as Expression,
+							mapper.GetValueMapper(param ?? source, typeof(TD), false, null, mapValues, defaultValue, srcMapValues));
+
+				return param == null ? expr : Expression.Invoke(Expression.Lambda<Func<TS,TD>>(expr, param), source);
+			}
+
+			public Expression SourceMapValues(
+				ExpressionMapper<TSource,TDest> mapper,
+				Expression                      source,
+				object                          nullValue,
+				object                          defaultValue,
+				MapValue[]                      srcMapValues)
+			{
+				var param =
+					//source.NodeType != ExpressionType.MemberAccess &&
+					source.NodeType != ExpressionType.Parameter    &&
+					source.NodeType != ExpressionType.Constant?
+						Expression.Parameter(typeof(TS), "p") :
+						null;
+
+				var expr = mapper.GetValueMapper(Expression.Constant(defaultValue), typeof(TD), true, nullValue, null, null, null);
+
+				for (var i = srcMapValues.Length - 1; i >= 0; i--)
+				{
+					var value = srcMapValues[i];
+
+					expr = Expression.Condition(
+						Expression.Equal(param ?? source, mapper.GetValueMapper(Expression.Constant(value.OrigValue), typeof(TS), false, null, null, null, null)),
+						mapper.GetValueMapper(Expression.Constant(value.MapValues[0]), typeof(TD), true, nullValue, null, null, null),
+						expr);
+				}
+
+				return param == null ? expr : Expression.Invoke(Expression.Lambda<Func<TS,TD>>(expr, param), source);
+			}
+
+			public Expression DestMapValues(
+				ExpressionMapper<TSource,TDest> mapper,
+				Expression                      source,
+				object                          nullValue,
+				MapValue[]                      mapValues,
+				object                          defaultValue)
+			{
+				var param =
+					//source.NodeType != ExpressionType.MemberAccess &&
+					source.NodeType != ExpressionType.Parameter    &&
+					source.NodeType != ExpressionType.Constant?
+						Expression.Parameter(typeof(TS), "p") :
+						null;
+
+				var expr = mapper.GetValueMapper(Expression.Constant(defaultValue), typeof(TD), true, nullValue, null, null, null);
+
+				for (var i = mapValues.Length - 1; i >= 0; i--)
+				{
+					var value = mapValues[i];
+					var orex  = null as Expression;
+
+					foreach (var mapValue in value.MapValues)
+					{
+						var ex = Expression.Equal(param ?? source, mapper.GetValueMapper(Expression.Constant(mapValue), typeof (TS), false, null, null, null, null));
+						orex = orex == null ? ex : Expression.OrElse(orex, ex);
+					}
+
+					if (orex != null)
+						expr = Expression.Condition(
+							orex,
+							mapper.GetValueMapper(Expression.Constant(value.OrigValue), typeof(TD), true, nullValue, null, null, null),
+							expr);
+				}
+
+				return param == null ? expr : Expression.Invoke(Expression.Lambda<Func<TS,TD>>(expr, param), source);
+			}
+		}
+
+		static IValueConvertHelper GetValueHelper(Type stype, Type dtype)
+		{
+			var type = typeof(ValueConvertHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), stype, dtype);
+			return ((IValueConvertHelper)Activator.CreateInstance(type));
+		}
+
+		#endregion
+
+		#region Object Converter
+
+		interface IConvertHelper
+		{
+			Expression MapObjects(ExpressionMapper<TSource,TDest> mapper, Expression source);
+			Expression MapLists  (ExpressionMapper<TSource,TDest> mapper, Expression source);
+		}
+
+		class ConvertHelper<TS,TD> : IConvertHelper
+			where TS : class
+			where TD : class
+		{
+			static TD MapCrossReferences(
+				MappingContext        ctx,
+				TS                    source,
+				Func<TS,TD>           func,
+				Func<object,object>   getCurrent,
+				Action<object,object> setCurrent)
+			{
+				if (source == null)
+					return null;
+
+				object dest;
+				List<Action<object,object>> list;
+
+				if (ctx.Objects.TryGetValue(source, out dest))
+				{
+					if (dest == null)
+					{
+						if (ctx.Crosses == null)
+							ctx.Crosses = new Dictionary<object,List<Action<object,object>>>();
+
+						if (!ctx.Crosses.TryGetValue(source, out list))
+							ctx.Crosses[source] = list = new List<Action<object,object>>();
+
+						var getParent = ctx.GetParent;
+
+						Action<object,object> setter = (obj,value) => setCurrent(getParent(obj), value);
+
+						list.Add(setter);
+					}
+
+					return (TD)dest;
+				}
+
+				var currParent = ctx.GetParent;
+
+				ctx.GetParent = p => getCurrent(currParent(p));
+				ctx.Objects.Add(source, null);
+				ctx.Objects[source] = dest = func(source);
+				ctx.GetParent = currParent;
+
+				if (ctx.Crosses != null && ctx.Crosses.TryGetValue(source, out list))
+				{
+					if (ctx.CrossActions == null)
+						ctx.CrossActions = new List<Action<object>>();
+
+					foreach (var action in list)
+					{
+						var setValue = action;
+
+						Action<object> f = parent => setValue(parent, dest);
+						ctx.CrossActions.Add(f);
+					}
+
+					ctx.Crosses.Remove(source);
+				}
+
+				return (TD)dest;
+			}
+
+			static TD MapObjects(TS source, Func<TS,TD> func)
+			{
+				return source == null ? null : func(source);
+			}
+
+			public Expression MapObjects(ExpressionMapper<TSource,TDest> mapper, Expression source)
+			{
+				var param = mapper._getCurrent == null ? (ParameterExpression)source : Expression.Parameter(source.Type, "source");
+
+				Expression expr;
+				object     m;
+
+				if (mapper._parameters.MapperList.TryGetValue(new { S = typeof(TS), D = typeof(TD) }, out m))
+				{
+					var map = (Mapper<TS,TD>)m;
+
+					if (map.Map == null)
+					{
+						expr = Expression.Invoke(
+							Expression.PropertyOrField(Expression.Constant(map), "Map"),
+							source, mapper._parameters.MappingContext);
+					}
+					else
+					{
+						expr = Expression.Invoke(Expression.Constant(map.Map), source, mapper._parameters.MappingContext);
+					}
+				}
+				else
+				{
+					var exmap = new ExpressionMapper<TS,TD>(mapper._parameters);
+					expr = exmap.GetMemberInit(param);
+				}
+
+				if (mapper._getCurrent == null)
+					return expr;
+
+				if (!mapper.HandleBackReferences)
+				{
+					Expression<Func<object>> func = () => MapObjects((TS)null, null);
+					return Expression.Call((MethodInfo)ReflectionHelper.MemeberInfo(func), source, Expression.Lambda<Func<TS,TD>>(expr, param));
+				}
+				else
+				{
+					mapper._parameters.UseContext = true;
+
+					Expression<Func<object>> func = () => MapCrossReferences(null, null, null, null, null);
+
+					return Expression.Call(
+						(MethodInfo)ReflectionHelper.MemeberInfo(func),
+						mapper._parameters.MappingContext,
+						source,
+						Expression.Lambda<Func<TS,TD>>(expr, param),
+						Expression.Constant(mapper._getCurrent),
+						Expression.Constant(mapper._setCurrent));
+				}
+			}
+
+			interface IItemHelper
+			{
+				Expression MapLists(ExpressionMapper<TSource,TDest> mapper, Expression source);
+			}
+
+			interface IClassItemHelper
+			{
+				MethodInfo GetObjectArrayInfo();
+				MethodInfo GetObjectListInfo(bool isList);
+			}
+
+			class ClassItemHelper<TSourceItem,TDestItem> : IClassItemHelper
+				where TSourceItem : class
+				where TDestItem   : class
+			{
+				static TDestItem[] MapObjectArray(MappingContext ctx, IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
+				{
+					if (source == null)
+						return null;
+
+					if (source is ICollection)
+					{
+						var col  = (ICollection)source;
+						var dest = new TDestItem[col.Count];
+						var n    = 0;
+
+						foreach (var item in source)
+						{
+							var current = n;
+							dest[n++] = ConvertHelper<TSourceItem,TDestItem>.MapCrossReferences(
+								ctx, item, itemMapper,
+								_ => dest[current],
+								(_,v) => { dest[current] = (TDestItem)v; });
+						}
+
+						return dest;
+					}
+					else
+					{
+						TDestItem[] dest = null;
+
+						var list = new List<TDestItem>();
+						var n    = 0;
+
+						foreach (var item in source)
+						{
+							var current = n;
+							list.Add(null);
+							list[n++] = ConvertHelper<TSourceItem,TDestItem>.MapCrossReferences(
+								ctx, item, itemMapper,
+								_ => dest == null ? list[current] : dest[current],
+								(_,v) => { if (dest == null) list[current] = (TDestItem)v; else dest[current] = (TDestItem)v; });
+						}
+
+						return dest = list.ToArray();
+					}
+				}
+
+				[UsedImplicitly]
+				static TList MapObjectList<TList>(MappingContext ctx, IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
+					where TList : class, IList<TDestItem>, new()
+				{
+					if (source == null)
+						return null;
+
+					var n    = 0;
+					var dest = source is ICollection && typeof(TList) == typeof(List<TDestItem>) ?
+						(TList)(IList<TDestItem>)new List<TDestItem>(((ICollection)source).Count) : new TList();
+
+					foreach (var item in source)
+					{
+						var current = n;
+						dest.Add(null);
+						dest[n++] = ConvertHelper<TSourceItem,TDestItem>.MapCrossReferences(
+							ctx, item, itemMapper,
+							_ => dest[current],
+							(_,v) => { dest[current] = (TDestItem)v; });
+					}
+
+					return dest;
+				}
+
+				public MethodInfo GetObjectArrayInfo()
+				{
+					Expression<Func<object>> arrMapper = () => MapObjectArray(null, null, null);
+					return (MethodInfo)ReflectionHelper.MemeberInfo(arrMapper);
+				}
+
+				public MethodInfo GetObjectListInfo(bool isList)
+				{
+					var method = typeof(ClassItemHelper<TSourceItem,TDestItem>).GetMethod("MapObjectList", BindingFlags.NonPublic | BindingFlags.Static);
+					return method.MakeGenericMethod(isList ? typeof (List<TDestItem>) : typeof (TD));
+				}
+			}
+
+			class ItemHelper<TSourceItem,TDestItem> : IItemHelper
+			{
+				static TDestItem[] MapScalarArray(IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
+				{
+					if (source == null)
+						return null;
+
+					if (source is ICollection)
+					{
+						var col  = (ICollection)source;
+						var dest = new TDestItem[col.Count];
+						var n    = 0;
+
+						foreach (var item in source)
+							dest[n++] = itemMapper(item);
+
+						return dest;
+					}
+
+					return source.Select(itemMapper).ToArray();
+				}
+
+				[UsedImplicitly]
+				static TList MapScalarList<TList>(IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
+					where TList : class, IList<TDestItem>, new()
+				{
+					if (source == null)
+						return null;
+
+					var dest = new TList();
+					var list = dest as List<TDestItem>;
+
+					if (list != null)
+						list.AddRange(source.Select(itemMapper));
+					else
+						foreach (var item in source)
+							dest.Add(itemMapper(item));
+
+					return dest;
+				}
+
+				public Expression MapLists(ExpressionMapper<TSource,TDest> mapper, Expression source)
+				{
+					var itemMapper =
+						new ExpressionMapper<TSourceItem,TDestItem>(mapper._parameters);
+
+					var itemParam = Expression.Parameter(typeof(TSourceItem), "item");
+					var itemExpr  = itemMapper.GetValueMapper(
+						itemParam,
+						typeof(TDestItem),
+						true,
+						mapper._parameters.MappingSchema.GetNullValue   (typeof(TDestItem)),
+						mapper._parameters.MappingSchema.GetMapValues   (typeof(TDestItem)),
+						mapper._parameters.MappingSchema.GetDefaultValue(typeof(TDestItem)),
+						mapper._parameters.MappingSchema.GetMapValues   (typeof(TSourceItem)));
+
+					var itemLambda = Expression.Lambda<Func<TSourceItem,TDestItem>>(itemExpr, itemParam);
+
+					var isSourceScalar = !typeof(TSourceItem).IsArray && TypeHelper.IsScalar(typeof(TSourceItem));
+					var isDestScalar   = !typeof(TDestItem).  IsArray && TypeHelper.IsScalar(typeof(TDestItem));
+
+					if (!mapper.HandleBackReferences || isSourceScalar || isDestScalar)
+					{
+						if (typeof (TD).IsArray)
+						{
+							Expression<Func<object>> arrMapper = () => MapScalarArray(null, null);
+							return Expression.Call((MethodInfo)ReflectionHelper.MemeberInfo(arrMapper), source, itemLambda);
+						}
+
+						var isList =
+							typeof (TD) == typeof (IEnumerable<TDestItem>) || typeof (TD) == typeof (ICollection<TDestItem>) ||
+							typeof (TD) == typeof (IList<TDestItem>)       || typeof (TD) == typeof (List<TDestItem>);
+
+						var method = typeof (ItemHelper<TSourceItem, TDestItem>).GetMethod("MapScalarList", BindingFlags.NonPublic | BindingFlags.Static);
+
+						method = method.MakeGenericMethod(isList ? typeof (List<TDestItem>) : typeof (TD));
+
+						return Expression.Call(method, source, itemLambda);
+					}
+					else
+					{
+						mapper._parameters.UseContext = true;
+
+						var type = typeof (ClassItemHelper<,>).MakeGenericType(
+							typeof (TSource), typeof (TDest),
+							typeof (TS), typeof (TD),
+							typeof (TSourceItem), typeof (TDestItem));
+
+						var helper = ((IClassItemHelper)Activator.CreateInstance(type));
+
+						if (typeof (TD).IsArray)
+							return Expression.Call(helper.GetObjectArrayInfo(), mapper._parameters.MappingContext, source, itemLambda);
+
+						var isList =
+							typeof (TD) == typeof (IEnumerable<TDestItem>) || typeof (TD) == typeof (ICollection<TDestItem>) ||
+							typeof (TD) == typeof (IList<TDestItem>) || typeof (TD) == typeof (List<TDestItem>);
+
+						return Expression.Call(helper.GetObjectListInfo(isList), mapper._parameters.MappingContext, source, itemLambda);
+					}
+				}
+			}
+
+			public Expression MapLists(ExpressionMapper<TSource,TDest> mapper, Expression source)
+			{
+				var ts = TypeHelper.GetGenericType(typeof(IEnumerable<>), typeof(TS)).GetGenericArguments()[0];
+				var td = TypeHelper.GetGenericType(typeof(IEnumerable<>), typeof(TD)).GetGenericArguments()[0];
+
+				var type = typeof(ItemHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), typeof(TS), typeof(TD), ts, td);
+				return ((IItemHelper)Activator.CreateInstance(type)).MapLists(mapper, source);
+			}
+		}
+
+		static IConvertHelper GetHelper(Type stype, Type dtype)
+		{
+			var type = typeof(ConvertHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), stype, dtype);
+			return ((IConvertHelper)Activator.CreateInstance(type));
+		}
+
+		#endregion
+
+		Expression GetValueMapper(
+			Expression source,
+			Type       dtype,
+			bool       checkNull,
+			object     nullValue,
+			MapValue[] destMapValues,
+			object     defaultValue,
+			MapValue[] srcMapValues)
+		{
+			var stype = source.Type;
+
+			var isSourceScalar = !stype.IsArray && TypeHelper.IsScalar(stype);
+			var isDestScalar   = !dtype.IsArray && TypeHelper.IsScalar(dtype);
+
+			if (dtype == typeof(object) || dtype == stype && (!DeepCopy || isSourceScalar))
+				return source;
+
+			var isSourceNullable = TypeHelper.IsNullableType(stype) || stype.IsClass;
+
+			if (checkNull && isSourceNullable && !TypeHelper.IsNullableType(dtype) && (isDestScalar || isSourceScalar))
+				return GetValueHelper(stype, dtype).CheckNull(this, source, nullValue, destMapValues, defaultValue, srcMapValues);
+
+			if (srcMapValues != null)
+				return GetValueHelper(stype, dtype).SourceMapValues(this, source, nullValue, defaultValue, srcMapValues);
+
+			if (destMapValues != null)
+				return GetValueHelper(stype, dtype).DestMapValues(this, source, nullValue, destMapValues, defaultValue);
+
+			if (dtype == typeof (string))
+				return
+					isSourceNullable
+						?
+							Expression.Condition(
+								Expression.Equal(source, Expression.Constant(null)),
+								Expression.Constant(null),
+								Expression.Call(source, "ToString", Array<Type>.Empty)) as Expression
+						:
+							Expression.Call(source, "ToString", Array<Type>.Empty);
+
+			if (!isDestScalar && !isSourceScalar)
+			{
+				if (TypeHelper.GetGenericType(typeof(IEnumerable<>), dtype) != null &&
+				    TypeHelper.GetGenericType(typeof(IEnumerable<>), stype) != null)
+					return GetHelper(stype, dtype).MapLists(this, source);
+
+				return GetHelper(stype, dtype).MapObjects(this, source);
+			}
+
+			try
+			{
+				return Expression.Convert(source, dtype);
+			}
+			catch (InvalidOperationException)
+			{
+			}
+
+			return GetValueHelper(stype, dtype).GetConverter(source);
+		}
+
+		IEnumerable<MemberBinding> GetBindings(Expression source)
+		{
+			var dest = _parameters.MappingSchema.GetObjectMapper(typeof(TDest));
+			var src  = _parameters.MappingSchema.GetObjectMapper(typeof(TSource));
+
+			foreach (MemberMapper dmm in dest)
+			{
+				if (!IncludeComplexMapping && dmm is MemberMapper.ComplexMapper)
+					continue;
+
+				var dma = dmm.MemberAccessor;
+
+				if (!dma.HasSetter)
+					continue;
+
+				var attr = dma.GetAttribute<ExpressionMapIgnoreAttribute>();
+
+				if (attr != null && attr.Ignore)
+					continue;
+
+				var smm = src[dmm.Name];
+
+				if (smm == null)
+					continue;
+
+				if (!IncludeComplexMapping && smm is MemberMapper.ComplexMapper)
+					continue;
+
+				var sma = smm.MemberAccessor;
+
+				if (!sma.HasGetter)
+					continue;
+
+				attr = sma.GetAttribute<ExpressionMapIgnoreAttribute>();
+
+				if (attr != null && attr.Ignore)
+					continue;
+
+				_getCurrent = dma.GetValue;
+				_setCurrent = dma.SetValue;
+
+				var bind = Expression.Bind(
+					dma.MemberInfo,
+					GetValueMapper(
+						Expression.PropertyOrField(source, sma.Name),
+						dma.Type,
+						true,
+						dmm.MapMemberInfo.NullValue,
+						dmm.MapMemberInfo.MapValues,
+						dmm.MapMemberInfo.DefaultValue,
+						smm.MapMemberInfo.MapValues));
+
+				yield return bind;
+			}
+
+			var destMembers = from m in ((IEnumerable<MemberAccessor>)dest.TypeAccessor) select m;
+
+			destMembers = destMembers.Except(dest.Select(mm => mm.MemberAccessor)).ToList();
+
+			var srcMembers =
+				(from m in ((IEnumerable<MemberAccessor>)src.TypeAccessor) select m)
+				.Except(src.Select(mm => mm.MemberAccessor))
+				.ToList();
+
+			foreach (var dma in destMembers)
+			{
+				if (!dma.HasSetter)
+					continue;
+
+				var sma = srcMembers.FirstOrDefault(mi => mi.Name == dma.Name);
+
+				if (sma == null || !sma.HasGetter)
+					continue;
+
+				_getCurrent = dma.GetValue;
+				_setCurrent = dma.SetValue;
+
+				var bind = Expression.Bind(
+					dma.MemberInfo,
+					GetValueMapper(
+						Expression.MakeMemberAccess(source, sma.MemberInfo),
+						dma.Type,
+						true,
+						_parameters.MappingSchema.GetNullValue   (dma.Type),
+						_parameters.MappingSchema.GetMapValues   (dma.Type),
+						_parameters.MappingSchema.GetDefaultValue(dma.Type),
+						_parameters.MappingSchema.GetMapValues   (sma.Type)));
+
+				yield return bind;
+			}
+		}
+
+		Expression GetMemberInit(ParameterExpression source)
+		{
+			var mapper = new Mapper<TSource,TDest>();
+
+			_parameters.MapperList.Add(new { S = typeof(TSource), D = typeof(TDest) }, mapper);
+
+			var dest = TypeAccessor<TDest>.Instance;
+			var expr = Expression.MemberInit(Expression.New(dest.Type), GetBindings(source));
+
+			mapper.Map = Expression.Lambda<Func<TSource,MappingContext,TDest>>(expr, source, _parameters.MappingContext).Compile();
+
+			return expr;
+		}
+
+		interface IAbstractHelper
+		{
+			Func<TSource,TDest> GetMapper(MappingParameters ps);
+		}
+
+		class AbstractHelper<TS,TD> : IAbstractHelper
+		{
+			public Func<TSource,TDest> GetMapper(MappingParameters ps)
+			{
+				var em     = new ExpressionMapper<TS,TD>(ps);
+				var mapper = em.GetMapper();
+
+				return source => (TDest)(object)mapper((TS)(object)source);
+			}
+		}
+
+		public Func<TSource,TDest> GetMapper()
+		{
+			if (typeof(TSource) == typeof(TDest) && !DeepCopy)
+				return s => (TDest)(object)s;
+
+			if (TypeHelper.IsAbstractClass(typeof(TSource)) || TypeHelper.IsAbstractClass(typeof(TDest)))
+			{
+				var st = TypeHelper.IsAbstractClass(typeof(TSource)) ? TypeAccessor<TSource>.Instance.Type : typeof(TSource);
+				var dt = TypeHelper.IsAbstractClass(typeof(TDest))   ? TypeAccessor<TDest>.  Instance.Type : typeof(TDest);
+
+				var type = typeof(AbstractHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), st, dt);
+				return ((IAbstractHelper)Activator.CreateInstance(type)).GetMapper(_parameters);
+			}
+
+			var parm = Expression.Parameter(typeof(TSource), "src");
+			var expr = GetValueMapper(
+				parm,
+				typeof(TDest),
+				true,
+				_parameters.MappingSchema.GetNullValue   (typeof(TDest)),
+				_parameters.MappingSchema.GetMapValues   (typeof(TDest)),
+				_parameters.MappingSchema.GetDefaultValue(typeof(TDest)),
+				_parameters.MappingSchema.GetMapValues   (typeof(TSource)));
+
+			if (_parameters.ContextParameterUsed)
+			{
+				var l = Expression.Lambda<Func<TSource,MappingContext,TDest>>(expr, parm, _parameters.MappingContext);
+				var f = l.Compile();
+
+				if (!_parameters.UseContext)
+					return s => f(s, null);
+
+				return s =>
+				{
+					var ctx  = new MappingContext
+					{
+						Objects   = new Dictionary<object,object>(10) { { s, null } },
+						GetParent = p => p,
+					};
+
+					var dest = f(s, ctx);
+
+					if (ctx.CrossActions != null)
+						foreach (var circle in ctx.CrossActions)
+							circle(dest);
+
+					if (ctx.Crosses != null)
+					{
+						List<Action<object,object>> list;
+
+						if (ctx.Crosses.TryGetValue(s, out list))
+							foreach (var action in list)
+								action(dest, dest);
+					}
+
+					return dest;
+				};
+			}
+
+			var lambda = Expression.Lambda<Func<TSource,TDest>>(expr, parm);
+
+			return lambda.Compile();
+		}
+	}
+}