Browse Source

重构表达式树对象映射器mapper,已支持可配置化。

懒得勤快 6 years ago
parent
commit
2436d98825
57 changed files with 3506 additions and 1553 deletions
  1. 7 11
      Masuit.Tools.Core/Files/SevenZipCompressor.cs
  2. 0 105
      Masuit.Tools.Core/Mapping/EnumerableCopier.cs
  3. 0 466
      Masuit.Tools.Core/Mapping/ExpressionGenericMapper.cs
  4. 0 40
      Masuit.Tools.Core/Mapping/MapClass.cs
  5. 0 50
      Masuit.Tools.Core/Mapping/MapperTools.cs
  6. 0 18
      Masuit.Tools.Core/Mapping/UnsupportedTypeException.cs
  7. 1 1
      Masuit.Tools.Core/Masuit.Tools.Core.csproj
  8. 0 164
      Masuit.Tools.UnitTest/ExpressionGenericMapperTest.cs
  9. 25 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/ClassDest.cs
  10. 13 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/ClassDest2.cs
  11. 21 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/ClassSource.cs
  12. 10 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/ClassSource2.cs
  13. 10 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/IClassDest2.cs
  14. 61 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/MapperConfigurationTestContainer.cs
  15. 60 0
      Masuit.Tools.UnitTest/Mapping/ClassTests/QueryableImplTest.cs
  16. 144 0
      Masuit.Tools.UnitTest/Mapping/Core/ConverterExpressionVisitorTest.cs
  17. 86 0
      Masuit.Tools.UnitTest/Mapping/Core/MapperConfigurationBaseTests.cs
  18. 191 0
      Masuit.Tools.UnitTest/Mapping/Core/MapperConfigurationTests.cs
  19. 37 0
      Masuit.Tools.UnitTest/Mapping/Core/MapperContainerTest.cs
  20. 85 0
      Masuit.Tools.UnitTest/Mapping/Core/MapperExpressionVisitorTest.cs
  21. 57 0
      Masuit.Tools.UnitTest/Mapping/Extentions/MapperExtentionsTest.cs
  22. 101 0
      Masuit.Tools.UnitTest/Mapping/Extentions/QueryableExtentionsTest.cs
  23. 115 0
      Masuit.Tools.UnitTest/Mapping/MapperTests.cs
  24. 15 1
      Masuit.Tools.UnitTest/Masuit.Tools.UnitTest.csproj
  25. 7 11
      Masuit.Tools/Files/SevenZipCompressor.cs
  26. 70 0
      Masuit.Tools/Mapping/Copier.cs
  27. 12 0
      Masuit.Tools/Mapping/Core/CreateConfig.cs
  28. 193 0
      Masuit.Tools/Mapping/Core/MapperConfiguration.cs
  29. 667 0
      Masuit.Tools/Mapping/Core/MapperConfigurationBase.cs
  30. 108 0
      Masuit.Tools/Mapping/Core/MapperConfigurationCollectionContainer.cs
  31. 35 0
      Masuit.Tools/Mapping/Core/PropertiesNotMapped.cs
  32. 59 0
      Masuit.Tools/Mapping/Core/TypePairMapper.cs
  33. 0 105
      Masuit.Tools/Mapping/EnumerableCopier.cs
  34. 56 0
      Masuit.Tools/Mapping/Exceptions/MapperExceptionBase.cs
  35. 55 0
      Masuit.Tools/Mapping/Exceptions/MapperExistException.cs
  36. 54 0
      Masuit.Tools/Mapping/Exceptions/MapperNotInitializedException.cs
  37. 46 0
      Masuit.Tools/Mapping/Exceptions/NoActionAfterMappingException.cs
  38. 54 0
      Masuit.Tools/Mapping/Exceptions/NoFoundMapperException.cs
  39. 53 0
      Masuit.Tools/Mapping/Exceptions/NotSameTypePropertyException.cs
  40. 54 0
      Masuit.Tools/Mapping/Exceptions/PropertyNoExistException.cs
  41. 59 0
      Masuit.Tools/Mapping/Exceptions/ReadOnlyPropertyException.cs
  42. 10 0
      Masuit.Tools/Mapping/ExpressionCpoier.cs
  43. 0 466
      Masuit.Tools/Mapping/ExpressionGenericMapper.cs
  44. 176 0
      Masuit.Tools/Mapping/ExpressionMapper.cs
  45. 77 0
      Masuit.Tools/Mapping/Extensions/ExpressionExtentions.cs
  46. 124 0
      Masuit.Tools/Mapping/Extensions/QueryableExtentions.cs
  47. 34 0
      Masuit.Tools/Mapping/Helper/MapperHelper.cs
  48. 64 0
      Masuit.Tools/Mapping/Helper/TypeSystem.cs
  49. 0 40
      Masuit.Tools/Mapping/MapClass.cs
  50. 0 50
      Masuit.Tools/Mapping/MapperTools.cs
  51. 0 18
      Masuit.Tools/Mapping/UnsupportedTypeException.cs
  52. 26 0
      Masuit.Tools/Mapping/Visitor/ChangParameterExpressionVisitor.cs
  53. 109 0
      Masuit.Tools/Mapping/Visitor/ConverterExpressionVisitor.cs
  54. 203 0
      Masuit.Tools/Mapping/Visitor/MapperExpressionVisitor.cs
  55. 35 0
      Masuit.Tools/Mapping/Visitor/PropertiesVisitor.cs
  56. 25 5
      Masuit.Tools/Masuit.Tools.csproj
  57. 2 2
      Masuit.Tools/Properties/AssemblyInfo.cs

+ 7 - 11
Masuit.Tools.Core/Files/SevenZipCompressor.cs

@@ -5,6 +5,7 @@ using SharpCompress.Common;
 using SharpCompress.Readers;
 using SharpCompress.Writers;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
@@ -181,15 +182,7 @@ namespace Masuit.Tools.Files
 
             if (remoteUrls.Any())
             {
-                //var dicList = remoteUrls.GroupBy(u => u.Authority).Select(g =>
-                //{
-                //    if (g.Count() > 1)
-                //    {
-                //        string pathname = new string(g.First().AbsolutePath.Substring(0, g.Min(s => s.AbsolutePath.Length)).TakeWhile((c, i) => g.All(s => s.AbsolutePath[i] == c)).ToArray());
-                //        return g.ToDictionary(s => s, s => HttpUtility.UrlDecode(s.AbsolutePath.Substring(pathname.Length)));
-                //    }
-                //    return g.ToDictionary(s => s, s => Path.GetFileName(HttpUtility.UrlDecode(s.AbsolutePath)));
-                //}).SelectMany(d => d).ToDictionary(x => x.Key, x => x.Value);
+                var streams = new ConcurrentDictionary<string, Stream>();
                 Parallel.ForEach(remoteUrls, url =>
                 {
                     _httpClient.GetAsync(url).ContinueWith(async t =>
@@ -200,12 +193,15 @@ namespace Masuit.Tools.Files
                             if (res.IsSuccessStatusCode)
                             {
                                 Stream stream = await res.Content.ReadAsStreamAsync();
-                                //archive.AddEntry(Path.Combine(rootdir, pathDic[new Uri(url).AbsolutePath.Trim('/')]), stream);
-                                archive.AddEntry(Path.Combine(rootdir, Path.GetFileName(HttpUtility.UrlDecode(url.AbsolutePath))), stream);
+                                streams[Path.Combine(rootdir, Path.GetFileName(HttpUtility.UrlDecode(url.AbsolutePath)))] = stream;
                             }
                         }
                     }).Wait();
                 });
+                foreach (var kv in streams)
+                {
+                    archive.AddEntry(kv.Key, kv.Value);
+                }
             }
 
             return archive;

+ 0 - 105
Masuit.Tools.Core/Mapping/EnumerableCopier.cs

@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-
-namespace Masuit.Tools.Mapping
-{
-    /// <summary>
-    /// 可遍历类型拷贝器
-    /// </summary>
-    internal class EnumerableCopier
-    {
-        private static readonly MethodInfo _copyArrayMethodInfo;
-
-        private static readonly MethodInfo _copyICollectionMethodInfo;
-
-        private static readonly Type _typeICollection = typeof(ICollection<>);
-
-        static EnumerableCopier()
-        {
-            Type type = typeof(EnumerableCopier);
-            _copyArrayMethodInfo = type.GetMethod(nameof(CopyArray));
-            _copyICollectionMethodInfo = type.GetMethod(nameof(CopyICollection));
-        }
-
-        /// <summary>
-        /// 根据IEnumerable的实现类类型选择合适的拷贝方法
-        /// </summary>
-        /// <param name="type">IEnumerable的实现类类型</param>
-        /// <returns>拷贝方法信息</returns>
-        public static MethodInfo GetMethondInfo(Type type)
-        {
-            if (type.IsArray)
-            {
-                return _copyArrayMethodInfo.MakeGenericMethod(type.GetElementType());
-            }
-
-            if (type.GetGenericArguments().Length > 0)
-            {
-                Type elementType = type.GetGenericArguments()[0];
-                if (_typeICollection.MakeGenericType(elementType).IsAssignableFrom(type))
-                {
-                    return _copyICollectionMethodInfo.MakeGenericMethod(type, elementType);
-                }
-            }
-
-            throw new UnsupportedTypeException(type);
-        }
-
-        /// <summary>
-        /// 拷贝List
-        /// </summary>
-        /// <typeparam name="T">源ICollection实现类类型</typeparam>
-        /// <typeparam name="TElement">源ICollection元素类型</typeparam>
-        /// <param name="source">源ICollection对象</param>
-        /// <returns>深拷贝完成的ICollection对象</returns>
-        public static T CopyICollection<T, TElement>(T source) where T : ICollection<TElement> where TElement : class
-        {
-            T result = (T)MapperTools.CreateNewInstance(source.GetType());
-
-            if (MapperTools.IsRefTypeExceptString(typeof(TElement)))
-            {
-                foreach (TElement item in source)
-                {
-                    result.Add(ExpressionGenericMapper<TElement, TElement>.Copy(item));
-                }
-            }
-            else
-            {
-                foreach (TElement item in source)
-                {
-                    result.Add(item);
-                }
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// 拷贝数组
-        /// </summary>
-        /// <typeparam name="TElement">源数组元素类型</typeparam>
-        /// <param name="source">源List</param>
-        /// <returns>深拷贝完成的数组</returns>
-        public static TElement[] CopyArray<TElement>(TElement[] source) where TElement : class
-        {
-            TElement[] result = new TElement[source.Length];
-            if (MapperTools.IsRefTypeExceptString(typeof(TElement)))
-            {
-                for (int i = 0; i < source.Length; i++)
-                {
-                    result[i] = ExpressionGenericMapper<TElement, TElement>.Copy(source[i]);
-                }
-            }
-            else
-            {
-                for (int i = 0; i < source.Length; i++)
-                {
-                    result[i] = source[i];
-                }
-            }
-
-            return result;
-        }
-    }
-}

+ 0 - 466
Masuit.Tools.Core/Mapping/ExpressionGenericMapper.cs

@@ -1,466 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations.Schema;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
-
-namespace Masuit.Tools.Mapping
-{
-    /// <summary>
-    /// 表达式树实体映射器
-    /// </summary>
-    /// <typeparam name="TSource"></typeparam>
-    /// <typeparam name="TDest"></typeparam>
-    public static class ExpressionGenericMapper<TSource, TDest> where TSource : class where TDest : class
-    {
-        // 缓存委托
-        private static Func<TSource, TDest> MapFunc;
-        private static Action<TSource, TDest> MapAction;
-        private static Func<TSource, TDest> _copyFunc;
-        private static Action<TSource, TDest> _copyAction;
-
-        /// <summary>
-        /// 对象映射
-        /// </summary>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static TDest Map(TSource source)
-        {
-            if (MapFunc == null)
-            {
-                MapFunc = GetMapFunc();
-            }
-
-            return MapFunc(source);
-        }
-
-        /// <summary>
-        /// 集合映射
-        /// </summary>
-        /// <param name="sources"></param>
-        /// <returns></returns>
-        public static List<TDest> MapList(IEnumerable<TSource> sources)
-        {
-            if (MapFunc == null)
-            {
-                MapFunc = GetMapFunc();
-            }
-
-            return sources.Select(MapFunc).ToList();
-        }
-
-        /// <summary>
-        /// 映射到已经实例化的对象
-        /// </summary>
-        /// <param name="source"></param>
-        /// <param name="target"></param>
-        public static void Map(TSource source, TDest target)
-        {
-            if (MapAction == null)
-            {
-                MapAction = GetMapAction();
-            }
-
-            MapAction(source, target);
-        }
-
-        private static Func<TSource, TDest> GetMapFunc()
-        {
-            var sourceType = typeof(TSource);
-            var targetType = typeof(TDest);
-
-            if (MapperTools.IsEnumerable(sourceType) || MapperTools.IsEnumerable(targetType))
-            {
-                throw new NotSupportedException("数组类型暂不支持对象映射,请使用List类型");
-            }
-
-            //Func委托传入变量
-            var parameter = Expression.Parameter(sourceType, "p");
-
-            var memberBindings = new List<MemberBinding>();
-            var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite);
-            foreach (var targetItem in targetTypes)
-            {
-                var sourceItem = sourceType.GetProperty(targetItem.Name);
-
-                //判断对象的读写权限
-                if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
-                {
-                    continue;
-                }
-
-                //标注NotMapped特性的属性忽略转换
-                if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
-                {
-                    continue;
-                }
-
-                var sourceProperty = Expression.Property(parameter, sourceItem);
-
-                //当非值类型且类型不相同时
-                if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType)
-                {
-                    //判断都是(非泛型、非数组)class
-                    if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass && !sourceItem.PropertyType.IsArray && !targetItem.PropertyType.IsArray && !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType)
-                    {
-                        var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        memberBindings.Add(Expression.Bind(targetItem, expression));
-                    }
-
-                    //集合数组类型的转换
-                    if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType))
-                    {
-                        var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        memberBindings.Add(Expression.Bind(targetItem, expression));
-                    }
-
-                    continue;
-                }
-
-                //可空类型转换到非可空类型,当可空类型值为null时,用默认值赋给目标属性;不为null就直接转换
-                if (MapperTools.IsNullableType(sourceItem.PropertyType) && !MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var hasValueExpression = Expression.Equal(Expression.Property(sourceProperty, "HasValue"), Expression.Constant(true));
-                    var conditionItem = Expression.Condition(hasValueExpression, Expression.Convert(sourceProperty, targetItem.PropertyType), Expression.Default(targetItem.PropertyType));
-                    memberBindings.Add(Expression.Bind(targetItem, conditionItem));
-                    continue;
-                }
-
-                //非可空类型转换到可空类型,直接转换
-                if (!MapperTools.IsNullableType(sourceItem.PropertyType) && MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var memberExpression = Expression.Convert(sourceProperty, targetItem.PropertyType);
-                    memberBindings.Add(Expression.Bind(targetItem, memberExpression));
-                    continue;
-                }
-
-                if (targetItem.PropertyType != sourceItem.PropertyType)
-                {
-                    continue;
-                }
-
-                memberBindings.Add(Expression.Bind(targetItem, sourceProperty));
-            }
-
-            //创建一个if条件表达式
-            var test = Expression.NotEqual(parameter, Expression.Constant(null, sourceType)); // p==null;
-            var ifTrue = Expression.MemberInit(Expression.New(targetType), memberBindings);
-            var condition = Expression.Condition(test, ifTrue, Expression.Constant(null, targetType));
-
-            var lambda = Expression.Lambda<Func<TSource, TDest>>(condition, parameter);
-            return lambda.Compile();
-        }
-
-        /// <summary>
-        /// 类型是clas时赋值
-        /// </summary>
-        /// <param name="sourceProperty"></param>
-        /// <param name="sourceType"></param>
-        /// <param name="targetType"></param>
-        /// <returns></returns>
-        private static Expression GetClassExpression(Expression sourceProperty, Type sourceType, Type targetType)
-        {
-            //条件p.Item!=null
-            var testItem = Expression.NotEqual(sourceProperty, Expression.Constant(null, sourceType));
-
-            //构造回调
-            var mapperType = typeof(ExpressionGenericMapper<,>).MakeGenericType(sourceType, targetType);
-            var iftrue = Expression.Call(mapperType.GetMethod(nameof(Map), new[]
-            {
-                sourceType
-            }), sourceProperty);
-            var conditionItem = Expression.Condition(testItem, iftrue, Expression.Constant(null, targetType));
-            return conditionItem;
-        }
-
-        /// <summary>
-        /// 类型为集合时赋值
-        /// </summary>
-        /// <param name="sourceProperty"></param>
-        /// <param name="sourceType"></param>
-        /// <param name="targetType"></param>
-        /// <returns></returns>
-        private static Expression GetListExpression(Expression sourceProperty, Type sourceType, Type targetType)
-        {
-            //条件p.Item!=null
-            var testItem = Expression.NotEqual(sourceProperty, Expression.Constant(null, sourceType));
-
-            //构造回调
-            var sourceArg = sourceType.IsArray ? sourceType.GetElementType() : sourceType.GetGenericArguments()[0];
-            var targetArg = targetType.IsArray ? targetType.GetElementType() : targetType.GetGenericArguments()[0];
-            var mapperType = typeof(ExpressionGenericMapper<,>).MakeGenericType(sourceArg, targetArg);
-            var mapperExecMap = Expression.Call(mapperType.GetMethod(nameof(MapList), new[]
-            {
-                sourceType
-            }), sourceProperty);
-            Expression iftrue;
-            if (targetType == mapperExecMap.Type)
-            {
-                iftrue = mapperExecMap;
-            }
-            else if (targetType.IsArray) //数组类型调用ToArray()方法
-            {
-                iftrue = Expression.Call(typeof(Enumerable), nameof(Enumerable.ToArray), new[]
-                {
-                    mapperExecMap.Type.GenericTypeArguments[0]
-                }, mapperExecMap);
-            }
-            else if (typeof(IDictionary).IsAssignableFrom(targetType))
-            {
-                iftrue = Expression.Constant(null, targetType); //字典类型不转换
-            }
-            else
-            {
-                iftrue = Expression.Convert(mapperExecMap, targetType);
-            }
-
-            var conditionItem = Expression.Condition(testItem, iftrue, Expression.Constant(null, targetType));
-            return conditionItem;
-        }
-
-        private static Action<TSource, TDest> GetMapAction()
-        {
-            var sourceType = typeof(TSource);
-            var targetType = typeof(TDest);
-
-            if (MapperTools.IsEnumerable(sourceType) || MapperTools.IsEnumerable(targetType))
-            {
-                throw new NotSupportedException("数组类型暂不支持对象映射,请使用List类型");
-            }
-
-            //Func委托传入变量
-            var sourceParameter = Expression.Parameter(sourceType, "p");
-            var targetParameter = Expression.Parameter(targetType, "t");
-
-            //创建一个表达式集合
-            var expressions = new List<Expression>();
-            var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite);
-            foreach (var targetItem in targetTypes)
-            {
-                var sourceItem = sourceType.GetProperty(targetItem.Name);
-
-                //判断对象的读写权限
-                if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
-                {
-                    continue;
-                }
-
-                //标注NotMapped特性的属性忽略转换
-                if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
-                {
-                    continue;
-                }
-
-                var sourceProperty = Expression.Property(sourceParameter, sourceItem);
-                var targetProperty = Expression.Property(targetParameter, targetItem);
-
-                //当非值类型且类型不相同时
-                if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType)
-                {
-                    //判断都是(非泛型、非数组)class
-                    if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass && !sourceItem.PropertyType.IsArray && !targetItem.PropertyType.IsArray && !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType)
-                    {
-                        var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        expressions.Add(Expression.Assign(targetProperty, expression));
-                    }
-
-                    //集合数组类型的转换
-                    if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType))
-                    {
-                        var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        expressions.Add(Expression.Assign(targetProperty, expression));
-                    }
-
-                    continue;
-                }
-
-                //可空类型转换到非可空类型,当可空类型值为null时,用默认值赋给目标属性;不为null就直接转换
-                if (MapperTools.IsNullableType(sourceItem.PropertyType) && !MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var hasValueExpression = Expression.Equal(Expression.Property(sourceProperty, "HasValue"), Expression.Constant(true));
-                    var conditionItem = Expression.Condition(hasValueExpression, Expression.Convert(sourceProperty, targetItem.PropertyType), Expression.Default(targetItem.PropertyType));
-                    expressions.Add(Expression.Assign(targetProperty, conditionItem));
-                    continue;
-                }
-
-                //非可空类型转换到可空类型,直接转换
-                if (!MapperTools.IsNullableType(sourceItem.PropertyType) && MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var memberExpression = Expression.Convert(sourceProperty, targetItem.PropertyType);
-                    expressions.Add(Expression.Assign(targetProperty, memberExpression));
-                    continue;
-                }
-
-                if (targetItem.PropertyType != sourceItem.PropertyType)
-                {
-                    continue;
-                }
-
-                expressions.Add(Expression.Assign(targetProperty, sourceProperty));
-            }
-
-            //当Target!=null判断source是否为空
-            var testSource = Expression.NotEqual(sourceParameter, Expression.Constant(null, sourceType));
-            var ifTrueSource = Expression.Block(expressions);
-            var conditionSource = Expression.IfThen(testSource, ifTrueSource);
-
-            //判断target是否为空
-            var tesTDest = Expression.NotEqual(targetParameter, Expression.Constant(null, targetType));
-            var conditionTarget = Expression.IfThen(tesTDest, conditionSource);
-            var lambda = Expression.Lambda<Action<TSource, TDest>>(conditionTarget, sourceParameter, targetParameter);
-            return lambda.Compile();
-        }
-
-        /// <summary>
-        /// 新建目标类型实例,并将源对象的属性值拷贝至目标对象的对应属性
-        /// </summary>
-        /// <param name="source">源对象实例</param>
-        /// <returns>深拷贝了源对象属性的目标对象实例</returns>
-        public static TDest Copy(TSource source)
-        {
-            if (source == null) return default(TDest);
-
-            // 因为对于泛型类型而言,每次传入不同的泛型参数都会调用静态构造函数,所以可以通过这种方式进行缓存
-            if (_copyFunc != null)
-            {
-                // 如果之前缓存过,则直接调用缓存的委托
-                return _copyFunc(source);
-            }
-
-            Type sourceType = typeof(TSource);
-            Type targetType = typeof(TDest);
-
-            var paramExpr = Expression.Parameter(sourceType, nameof(source));
-
-            Expression bodyExpr;
-
-            // 如果对象可以遍历(目前只支持数组和ICollection<T>实现类)
-            if (sourceType == targetType && MapperTools.IsIEnumerableExceptString(sourceType))
-            {
-                bodyExpr = Expression.Call(null, EnumerableCopier.GetMethondInfo(sourceType), paramExpr);
-            }
-            else
-            {
-                var memberBindings = new List<MemberBinding>();
-                // 遍历目标对象的所有属性信息
-                foreach (var targetPropInfo in targetType.GetProperties())
-                {
-                    // 从源对象获取同名的属性信息
-                    var sourcePropInfo = sourceType.GetProperty(targetPropInfo.Name);
-
-                    Type sourcePropType = sourcePropInfo?.PropertyType;
-                    Type targetPropType = targetPropInfo.PropertyType;
-
-                    // 只在满足以下三个条件的情况下进行拷贝
-                    // 1.源属性类型和目标属性类型一致
-                    // 2.源属性可读
-                    // 3.目标属性可写
-                    if (sourcePropType == targetPropType && sourcePropInfo.CanRead && targetPropInfo.CanWrite)
-                    {
-                        // 获取属性值的表达式
-                        Expression expression = Expression.Property(paramExpr, sourcePropInfo);
-
-                        // 如果目标属性是值类型或者字符串,则直接做赋值处理
-                        // 暂不考虑目标值类型有非字符串的引用类型这种特殊情况
-                        // 非字符串引用类型做递归处理
-                        if (MapperTools.IsRefTypeExceptString(targetPropType))
-                        {
-                            // 进行递归
-                            if (MapperTools.IsRefTypeExceptString(targetPropType))
-                            {
-                                expression = Expression.Call(null, GetCopyMethodInfo(sourcePropType, targetPropType), expression);
-                            }
-                        }
-
-                        memberBindings.Add(Expression.Bind(targetPropInfo, expression));
-                    }
-                }
-
-                bodyExpr = Expression.MemberInit(Expression.New(targetType), memberBindings);
-            }
-
-            var lambdaExpr = Expression.Lambda<Func<TSource, TDest>>(bodyExpr, paramExpr);
-
-            _copyFunc = lambdaExpr.Compile();
-            return _copyFunc(source);
-        }
-
-        /// <summary>
-        /// 新建目标类型实例,并将源对象的属性值拷贝至目标对象的对应属性
-        /// </summary>
-        /// <param name="source">源对象实例</param>
-        /// <param name="target">目标对象实例</param>
-        public static void Copy(TSource source, TDest target)
-        {
-            if (source == null) return;
-
-            // 因为对于泛型类型而言,每次传入不同的泛型参数都会调用静态构造函数,所以可以通过这种方式进行缓存
-            // 如果之前缓存过,则直接调用缓存的委托
-            if (_copyAction != null)
-            {
-                _copyAction(source, target);
-                return;
-            }
-
-            Type sourceType = typeof(TSource);
-            Type targetType = typeof(TDest);
-
-            // 如果双方都可以被遍历
-            if (MapperTools.IsIEnumerableExceptString(sourceType) && MapperTools.IsIEnumerableExceptString(targetType))
-            {
-                // TODO
-                // 向已存在的数组或者ICollection<T>拷贝的功能暂不支持
-            }
-            else
-            {
-                var paramSourceExpr = Expression.Parameter(sourceType, nameof(source));
-                var paramTargetExpr = Expression.Parameter(targetType, nameof(target));
-
-                var binaryExpressions = new List<Expression>();
-                // 遍历目标对象的所有属性信息
-                foreach (var targetPropInfo in targetType.GetProperties())
-                {
-                    // 从源对象获取同名的属性信息
-                    var sourcePropInfo = sourceType.GetProperty(targetPropInfo.Name);
-
-                    Type sourcePropType = sourcePropInfo?.PropertyType;
-                    Type targetPropType = targetPropInfo.PropertyType;
-
-                    // 只在满足以下三个条件的情况下进行拷贝
-                    // 1.源属性类型和目标属性类型一致
-                    // 2.源属性可读
-                    // 3.目标属性可写
-                    if (sourcePropType == targetPropType && sourcePropInfo.CanRead && targetPropInfo.CanWrite)
-                    {
-                        // 获取属性值的表达式
-                        Expression expression = Expression.Property(paramSourceExpr, sourcePropInfo);
-                        Expression targetPropExpr = Expression.Property(paramTargetExpr, targetPropInfo);
-
-                        // 如果目标属性是值类型或者字符串,则直接做赋值处理
-                        // 暂不考虑目标值类型有非字符串的引用类型这种特殊情况
-                        if (MapperTools.IsRefTypeExceptString(targetPropType))
-                        {
-                            expression = Expression.Call(null, GetCopyMethodInfo(sourcePropType, targetPropType), expression);
-                        }
-
-                        binaryExpressions.Add(Expression.Assign(targetPropExpr, expression));
-                    }
-                }
-
-                Expression bodyExpr = Expression.Block(binaryExpressions);
-
-                var lambdaExpr = Expression.Lambda<Action<TSource, TDest>>(bodyExpr, paramSourceExpr, paramTargetExpr);
-
-                _copyAction = lambdaExpr.Compile();
-                _copyAction(source, target);
-            }
-        }
-
-        private static MethodInfo GetCopyMethodInfo(Type source, Type target) => typeof(ExpressionGenericMapper<,>).MakeGenericType(source, target).GetMethod(nameof(Copy), new[]
-        {
-            source
-        });
-    }
-}

+ 0 - 40
Masuit.Tools.Core/Mapping/MapClass.cs

@@ -1,40 +0,0 @@
-using System.Collections.Generic;
-
-namespace Masuit.Tools.Mapping
-{
-    /// <summary>
-    /// 映射操作类
-    /// </summary>
-    public static class MapClass
-    {
-        /// <summary>
-        /// 将对象TSource转换为TDest
-        /// </summary>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static TDest Map<TSource, TDest>(this TSource source) where TDest : class where TSource : class => ExpressionGenericMapper<TSource, TDest>.Map(source);
-
-        /// <summary>
-        /// 集合元素映射
-        /// </summary>
-        /// <param name="sources"></param>
-        /// <returns></returns>
-        public static List<TDest> MapList<TSource, TDest>(this IEnumerable<TSource> sources) where TDest : class where TSource : class => ExpressionGenericMapper<TSource, TDest>.MapList(sources);
-
-        /// <summary>
-        /// 将对象TSource的值赋给给TDest
-        /// </summary>
-        /// <param name="source"></param>
-        /// <param name="target"></param>
-        public static void MapTo<TSource, TDest>(this TSource source, TDest target) where TSource : class where TDest : class => ExpressionGenericMapper<TSource, TDest>.Map(source, target);
-
-        /// <summary>
-        /// 复制一个新对象
-        /// </summary>
-        /// <typeparam name="TSource"></typeparam>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static TSource Copy<TSource>(this TSource source) where TSource : class => ExpressionGenericMapper<TSource, TSource>.Copy(source);
-
-    }
-}

+ 0 - 50
Masuit.Tools.Core/Mapping/MapperTools.cs

@@ -1,50 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Concurrent;
-using System.Linq;
-using System.Linq.Expressions;
-
-namespace Masuit.Tools
-{
-    /// <summary>
-    /// 工具类
-    /// </summary>
-    internal static class MapperTools
-    {
-        private static readonly Type _typeString = typeof(string);
-
-        private static readonly Type _typeIEnumerable = typeof(IEnumerable);
-
-        private static readonly ConcurrentDictionary<Type, Func<object>> _ctors = new ConcurrentDictionary<Type, Func<object>>();
-
-        /// <summary>
-        /// 判断是否是string以外的引用类型
-        /// </summary>
-        /// <returns>True:是string以外的引用类型,False:不是string以外的引用类型</returns>
-        public static bool IsRefTypeExceptString(Type type) => !type.IsValueType && type != _typeString;
-
-        /// <summary>
-        /// 判断是否是string以外的可遍历类型
-        /// </summary>
-        /// <returns>True:是string以外的可遍历类型,False:不是string以外的可遍历类型</returns>
-        public static bool IsIEnumerableExceptString(Type type) => _typeIEnumerable.IsAssignableFrom(type) && type != _typeString;
-
-        /// <summary>
-        /// 创建指定类型实例
-        /// </summary>
-        /// <param name="type">类型信息</param>
-        /// <returns>指定类型的实例</returns>
-        public static object CreateNewInstance(Type type) => _ctors.GetOrAdd(type, t => Expression.Lambda<Func<object>>(Expression.New(t)).Compile())();
-
-        public static bool IsNullableType(Type type)
-        {
-            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
-        }
-
-        public static bool IsEnumerable(Type type)
-        {
-            return type.IsArray || type.GetInterfaces().Any(x => x == typeof(ICollection) || x == typeof(IEnumerable));
-        }
-
-    }
-}

+ 0 - 18
Masuit.Tools.Core/Mapping/UnsupportedTypeException.cs

@@ -1,18 +0,0 @@
-using System;
-
-namespace Masuit.Tools
-{
-    /// <summary>
-    /// 对尚不支持的类型进行拷贝时抛出的异常
-    /// </summary>
-    public class UnsupportedTypeException : Exception
-    {
-        /// <summary>
-        /// 用指定的类型初始化 DeepCopier.UnsupportedTypeException 类的新实例
-        /// </summary>
-        /// <param name="type">暂不支持的类型信息</param>
-        public UnsupportedTypeException(Type type) : base($"类型 [{type.Name}] 尚未实现支持!")
-        {
-        }
-    }
-}

+ 1 - 1
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <TargetFramework>netcoreapp2.1</TargetFramework>
-    <Version>2.2.3.5</Version>
+    <Version>2.2.4</Version>
     <Authors>懒得勤快</Authors>
     <Company>masuit.com</Company>
     <Description>包含一些常用的操作类,大都是静态类,加密解密,反射操作,硬件信息,字符串扩展方法,日期时间扩展操作,大文件拷贝,图像裁剪,html处理,验证码、NoSql等常用封装。

+ 0 - 164
Masuit.Tools.UnitTest/ExpressionGenericMapperTest.cs

@@ -1,164 +0,0 @@
-using Masuit.Tools.Mapping;
-using Masuit.Tools.UnitTest.TestClasses;
-using System.Collections.Generic;
-using Xunit;
-
-namespace Masuit.Tools.UnitTest
-{
-    public class ExpressionGenericMapperTest
-    {
-        /// <summary>
-        /// 测试拷贝一个对象本身
-        /// </summary>
-        [Fact]
-        public void TestSelfCopy()
-        {
-            TestClassA a = new TestClassA()
-            {
-                TestClassC = new TestClassC()
-                {
-                    MyProperty = "string"
-                },
-                List = new List<TestClassC>()
-                {
-                    new TestClassC(){MyProperty = "cstring"}
-                }
-            };
-
-            var a2 = a.Copy();
-
-            Assert.Equal(a.TestClassC.MyProperty, a2.TestClassC.MyProperty);
-            Assert.Equal(a.List.Count, a2.List.Count);
-        }
-
-        /// <summary>
-        /// 测试拷贝简单的属性
-        /// </summary>
-        [Fact]
-        public void TestSimpleProperties()
-        {
-            TestClassA a = new TestClassA
-            {
-                MyProperty = "string"
-            };
-
-            TestClassB b = a.Map<TestClassA, TestClassB>();
-            Assert.Equal(a.MyProperty, b.MyProperty);
-        }
-
-        /// <summary>
-        /// 测试拷贝引用类型的属性
-        /// </summary>
-        [Fact]
-        public void TestRefTypeProperties()
-        {
-            TestClassA a = new TestClassA()
-            {
-                TestClassC = new TestClassC()
-                {
-                    MyProperty = "string"
-                },
-                List = new List<TestClassC>()
-                {
-                    new TestClassC(){MyProperty = "cstring"}
-                }
-            };
-            var b = a.Map<TestClassA, TestClassB>();
-            Assert.Equal(a.MyProperty, b.MyProperty);
-            Assert.Equal(a.TestClassC.MyProperty, b.TestClassC.MyProperty);
-            Assert.Equal(a.List.Count, b.List.Count);
-        }
-
-        /// <summary>
-        /// 测试可遍历的属性
-        /// </summary>
-        [Fact]
-        public void TestEnumableProperties()
-        {
-            TestClassA a = new TestClassA()
-            {
-                TestClassC = new TestClassC()
-                {
-                    MyProperty = "string"
-                },
-                List = new List<TestClassC>()
-                {
-                    new TestClassC(){MyProperty = "cstring"},
-                    new TestClassC(){MyProperty = "cstring"},
-                },
-                MyProperty = "string",
-                Array = new[]
-                {
-                    new TestClassC()
-                    {
-                        MyProperty = "string",
-                        Obj = new TestClassD()
-                        {
-                            MyProperty = "sstring"
-                        }
-                    },
-                    new TestClassC()
-                    {
-                        MyProperty = "string",
-                        Obj = new TestClassD()
-                        {
-                            MyProperty = "sstring"
-                        }
-                    },
-                }
-            };
-            var b = a.Map<TestClassA, TestClassB>();
-            Assert.Equal(a.MyProperty, b.MyProperty);
-            Assert.Equal(a.TestClassC.MyProperty, b.TestClassC.MyProperty);
-            Assert.Equal(a.List.Count, b.List.Count);
-            Assert.Equal(a.Array.Length, b.Array.Length);
-        }
-
-
-        /// <summary>
-        /// 测试向已存在的对象拷贝属性值
-        /// </summary>
-        [Fact]
-        public void TestCopyToExistingObject()
-        {
-            TestClassA a = new TestClassA()
-            {
-                TestClassC = new TestClassC()
-                {
-                    MyProperty = "string"
-                },
-                List = new List<TestClassC>()
-                {
-                    new TestClassC(){MyProperty = "cstring"},
-                    new TestClassC(){MyProperty = "cstring"},
-                },
-                MyProperty = "string",
-                Array = new[]
-                {
-                    new TestClassC()
-                    {
-                        MyProperty = "string",
-                        Obj = new TestClassD()
-                        {
-                            MyProperty = "sstring"
-                        }
-                    },
-                    new TestClassC()
-                    {
-                        MyProperty = "string",
-                        Obj = new TestClassD()
-                        {
-                            MyProperty = "sstring"
-                        }
-                    },
-                }
-            };
-            var b = new TestClassB();
-            a.MapTo(b);
-            Assert.Equal(a.MyProperty, b.MyProperty);
-            Assert.Equal(a.TestClassC.MyProperty, b.TestClassC.MyProperty);
-            Assert.Equal(a.List.Count, b.List.Count);
-            Assert.Equal(a.Array.Length, b.Array.Length);
-        }
-    }
-}

+ 25 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/ClassDest.cs

@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public class ClassDest
+    {
+
+        public int PropInt1 { get; set; }
+        public int PropInt2 { get; set; }
+
+        public string PropString { get; set; }
+        public string PropString2 { get; set; }
+
+
+        public int RealOnlyPropInt1 { get; }
+
+        public ClassDest2 ClassDestEntityBase { get; set; }
+        public List<ClassDest2> ListProp { get; set; }
+
+        public List<string> ListString { get; set; }
+        public ClassDest2 SubClass { get; set; }
+        public ClassDest2 SubClass2 { get; set; }
+        public int CountListProp { get; set; }
+    }
+}

+ 13 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/ClassDest2.cs

@@ -0,0 +1,13 @@
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public class ClassDest2 : IClassDest2
+    {
+
+        public int PropInt1 { get; set; }
+        public int PropInt2 { get; set; }
+        public string PropString2 { get; set; }
+
+        public ClassSource ClassSourceProp { get; set; }
+
+    }
+}

+ 21 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/ClassSource.cs

@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public class ClassSource
+    {
+        public int PropInt1 { get; set; }
+        public int PropSourceInt1 { get; set; }
+        public string PropString1 { get; set; }
+
+        public string PropString { get; set; }
+
+        public string PropString2 { get; set; }
+        public List<ClassSource2> ListProp { get; set; }
+
+        public List<string> ListString { get; set; }
+        public ClassSource Same { get; set; }
+
+        public ClassSource2 SubClass { get; set; }
+    }
+}

+ 10 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/ClassSource2.cs

@@ -0,0 +1,10 @@
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public class ClassSource2
+    {
+        public int PropInt1 { get; set; }
+        public int PropSourceInt1 { get; set; }
+        public string PropString1 { get; set; }
+        public ClassSource SameParent { get; set; }
+    }
+}

+ 10 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/IClassDest2.cs

@@ -0,0 +1,10 @@
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public interface IClassDest2
+    {
+        ClassSource ClassSourceProp { get; set; }
+        int PropInt1 { get; set; }
+        int PropInt2 { get; set; }
+        string PropString2 { get; set; }
+    }
+}

+ 61 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/MapperConfigurationTestContainer.cs

@@ -0,0 +1,61 @@
+using Masuit.Tools.Mapping.Core;
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public class MapperConfigurationTestContainer : MapperConfiguration<ClassSource, ClassDest>
+    {
+        public MapperConfigurationTestContainer() : base("sTest")
+        {
+        }
+
+        public int GetIgnoreCount()
+        {
+            return PropertiesToIgnore.Count;
+        }
+
+        public int GetAfterMapActionCount()
+        {
+            return actionsAfterMap.Count;
+        }
+
+        public MapperConfigurationBase GetMapperTest(Type tSource, Type tDest, bool throwExceptionOnNoFound)
+        {
+            return GetMapper(tSource, tDest, throwExceptionOnNoFound);
+        }
+
+        public void CheckAndConfigureMappingTest(Tuple<Expression, Expression, bool, string> configExpression)
+        {
+            CheckAndConfigureMapping(ref configExpression);
+        }
+
+        public PropertyInfo GetPropertyInfoTest(LambdaExpression expression)
+        {
+            return GetPropertyInfo(expression);
+        }
+
+
+        public void CreateCommonMemberTest()
+        {
+            CreateCommonMember();
+        }
+
+        public void CheckAndRemoveMemberDestTest(string propertyName)
+        {
+            CheckAndRemoveMemberDest(propertyName);
+        }
+
+
+        public void CreateMemberAssignementForExistingTargetTest()
+        {
+            CreateMemberAssignementForExistingTarget();
+        }
+
+        public Delegate GetDelegateForExistingTargetTest()
+        {
+            return GetDelegateForExistingTarget();
+        }
+    }
+}

+ 60 - 0
Masuit.Tools.UnitTest/Mapping/ClassTests/QueryableImplTest.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.UnitTest.Mapping.ClassTests
+{
+    public class QueryableImplTest<T> : IOrderedQueryable<T>
+    {
+        public QueryableImplTest()
+        {
+            Provider = new QueryProviderImplTest();
+            Expression = Expression.Constant(this);
+        }
+
+        public QueryableImplTest(Expression expression)
+        : this()
+        {
+            Expression = expression;
+        }
+        public Type ElementType => typeof(T);
+
+        public Expression Expression { get; }
+
+        public IQueryProvider Provider { get; }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return Provider.CreateQuery<T>(Expression).GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return Provider.CreateQuery<T>(Expression).GetEnumerator();
+        }
+    }
+    public class QueryProviderImplTest : IQueryProvider
+    {
+        public IQueryable CreateQuery(Expression expression)
+        {
+            return null;
+        }
+
+        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
+        {
+            return new QueryableImplTest<TElement>(expression);
+        }
+
+        public object Execute(Expression expression)
+        {
+            return null;
+        }
+
+        public TResult Execute<TResult>(Expression expression)
+        {
+            return default(TResult);
+        }
+    }
+}

+ 144 - 0
Masuit.Tools.UnitTest/Mapping/Core/ConverterExpressionVisitorTest.cs

@@ -0,0 +1,144 @@
+using Masuit.Tools.Mapping;
+using Masuit.Tools.Mapping.Visitor;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.UnitTest.Mapping.Core
+{
+    [TestClass]
+    public class ConverterExpressionVisitorTest
+    {
+        [ClassInitialize]
+        public static void Init(TestContext context)
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2).ReverseMap();
+            ExpressionMapper.CreateMap<ClassDest2, ClassSource2>().ForMember(s => s.PropString2, d => d.PropString1).ReverseMap();
+            ExpressionMapper.Initialize();
+        }
+
+        [ClassCleanup]
+        public static void Clean()
+        {
+            ExpressionMapper.Reset();
+        }
+
+        [TestMethod]
+        public void VisitMember_Expression_SimpleProperty_Success()
+        {
+            Init(null);
+            Expression<Func<ClassDest, bool>> expected = x => x.PropString2 == "test";
+            ConverterExpressionVisitor visitor = new ConverterExpressionVisitor(GetParametersDictionnary(expected, typeof(ClassSource)), typeof(ClassSource));
+
+            var actual = visitor.Visit(expected);
+
+            var test = actual as BinaryExpression;
+            Assert.IsNotNull(test);
+            Assert.IsInstanceOfType(test.Left, typeof(MemberExpression));
+            Assert.AreEqual((test.Left as MemberExpression).Member.ReflectedType, typeof(ClassSource));
+            Assert.AreEqual((test.Left as MemberExpression).Member.Name, "PropString1");
+            Clean();
+        }
+
+        [TestMethod]
+        public void VisitMember_Expression_SubClassProperty_Success()
+        {
+            Init(null);
+
+            Expression<Func<ClassSource, bool>> expected = x => x.SubClass.PropString1 == "test";
+            ConverterExpressionVisitor visitor = new ConverterExpressionVisitor(GetParametersDictionnary(expected, typeof(ClassDest)), typeof(ClassDest));
+
+            var actual = visitor.Visit(expected);
+            var test = actual as BinaryExpression;
+            Assert.IsNotNull(test);
+            Assert.IsInstanceOfType(test.Left, typeof(MemberExpression));
+            Assert.AreEqual((test.Left as MemberExpression).Member.ReflectedType, typeof(ClassDest2));
+            Assert.AreEqual((test.Left as MemberExpression).Member.Name, "PropString2");
+        }
+
+
+        [TestMethod]
+        public void VisitMember_Expression_SimpleProperty_MultiCondition_Success()
+        {
+            Init(null);
+            Expression<Func<ClassDest, bool>> expected = x => x.PropString2 == "test" && x.PropString2 == "test3";
+            ConverterExpressionVisitor visitor = new ConverterExpressionVisitor(GetParametersDictionnary(expected, typeof(ClassSource)), typeof(ClassSource));
+
+            var actual = visitor.Visit(expected);
+
+            var test = actual as BinaryExpression;
+            Assert.IsNotNull(test);
+            Assert.IsInstanceOfType(test.Left, typeof(BinaryExpression));
+            Assert.IsInstanceOfType(test.Right, typeof(BinaryExpression));
+            Assert.AreEqual(((test.Left as BinaryExpression).Left as MemberExpression).Member.Name, "PropString1");
+            Assert.AreEqual(((test.Right as BinaryExpression).Left as MemberExpression).Member.Name, "PropString1");
+            Clean();
+        }
+
+        [TestMethod]
+        public void VisitMember_Expression_SimpleProperty_MultiCondition_SubClass_Success()
+        {
+            Init(null);
+            Expression<Func<ClassDest, bool>> expected = x => x.PropString2 == "test" && x.SubClass.PropString2 == "test";
+            ConverterExpressionVisitor visitor = new ConverterExpressionVisitor(GetParametersDictionnary(expected, typeof(ClassSource)), typeof(ClassSource));
+
+            var actual = visitor.Visit(expected);
+
+            var test = actual as BinaryExpression;
+            Assert.IsNotNull(test);
+            Assert.IsInstanceOfType(test.Left, typeof(BinaryExpression));
+            Assert.IsInstanceOfType(test.Right, typeof(BinaryExpression));
+            Assert.AreEqual(((test.Left as BinaryExpression).Left as MemberExpression).Member.Name, "PropString1");
+            Assert.AreEqual(((test.Right as BinaryExpression).Left as MemberExpression).Member.Name, "PropString1");
+            Clean();
+        }
+
+        [TestMethod]
+        public void VisitMember_Expression_ExtentionMethod_Success()
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassDest, ClassSource>().ForMember(s => s.PropString2, d => d.PropString1).ForMember(s => s.SubClass, d => d.SubClass).ForMember(s => s.CountListProp, d => d.ListProp.Count());
+            Expression<Func<ClassDest, bool>> expected = x => x.CountListProp > 0;
+            ConverterExpressionVisitor visitor = new ConverterExpressionVisitor(GetParametersDictionnary(expected, typeof(ClassSource)), typeof(ClassSource));
+
+            var actual = visitor.Visit(expected);
+
+            var test = actual as BinaryExpression;
+            Assert.IsNotNull(test);
+
+            Clean();
+        }
+
+        [TestMethod]
+        public void Visit_Null_Expression_Success()
+        {
+            Init(null);
+            Expression<Func<ClassDest, bool>> expected = null;
+            ConverterExpressionVisitor visitor = new ConverterExpressionVisitor(GetParametersDictionnary(expected, typeof(ClassSource)), typeof(ClassSource));
+
+            var actual = visitor.Visit(expected);
+
+            Assert.IsNull(actual);
+        }
+
+        private Dictionary<Expression, Expression> GetParametersDictionnary<TFrom>(Expression<TFrom> from, Type toType)
+        {
+            Dictionary<Expression, Expression> parameterMap = new Dictionary<Expression, Expression>();
+            if (from != null)
+            {
+                ParameterExpression[] newParams = new ParameterExpression[from.Parameters.Count];
+                for (int i = 0; i < newParams.Length; i++)
+                {
+                    newParams[i] = Expression.Parameter(toType, from.Parameters[i].Name);
+                    parameterMap[from.Parameters[i]] = newParams[i];
+                }
+            }
+
+            return parameterMap;
+        }
+    }
+}

+ 86 - 0
Masuit.Tools.UnitTest/Mapping/Core/MapperConfigurationBaseTests.cs

@@ -0,0 +1,86 @@
+using Masuit.Tools.Mapping;
+using Masuit.Tools.Mapping.Core;
+using Masuit.Tools.Mapping.Exceptions;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.UnitTest.Mapping.Core
+{
+    [TestClass]
+    public class MapperConfigurationBaseTests
+    {
+
+        [TestMethod, TestCategory("Constructor")]
+        public void NewMapperConfigurationBase_SetProperties()
+        {
+            MapperConfigurationBase actual = new MapperConfiguration<ClassSource, ClassDest>("sourceTest");
+            Assert.IsNotNull(actual.MemberToMapForNew);
+            Assert.AreEqual(actual.TargetType, typeof(ClassDest));
+            Assert.AreEqual(actual.SourceType, typeof(ClassSource));
+        }
+
+        [TestMethod, TestCategory("GetDestinationType")]
+        public void GetDestinationType_WithoutServiceConstructor()
+        {
+            var mapper = new MapperConfiguration<ClassSource, ClassDest>("sourceTest");
+            var actual = mapper.GetDestinationType();
+
+            Assert.AreEqual(actual, typeof(ClassDest));
+        }
+
+        [TestMethod, TestCategory("GetDestinationType")]
+        public void GetDestinationType_WithServiceConstructor()
+        {
+            ExpressionMapper.ConstructServicesUsing((x) => new ClassDest2());
+
+            var mapper = ExpressionMapper.CreateMap<ClassSource2, IClassDest2>().ConstructUsingServiceLocator();
+            ExpressionMapper.Initialize();
+            var actual = mapper.GetDestinationType();
+
+            Assert.AreEqual(actual, typeof(ClassDest2));
+            ExpressionMapper.Reset();
+        }
+
+
+        [TestMethod, TestCategory("GetDelegate"), ExpectedException(typeof(MapperNotInitializedException))]
+        public void GetDelegate_MapperNotInitialise_Exception()
+        {
+            MapperConfigurationBase mapper = new MapperConfiguration<ClassSource, ClassDest>("sourceTest");
+            mapper.GetDelegate();
+        }
+
+        [TestMethod, TestCategory("CheckAndConfigureTuple")]
+        public void CheckAndConfigureMappingTest_List_NotSameType_Success()
+        {
+            ExpressionMapper.Reset();
+            ExpressionMapper.CreateMap<ClassSource2, ClassDest2>();
+
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            MapperConfigurationCollectionContainer.Instance.Add(expected);
+            ExpressionMapper.Initialize();
+            Expression<Func<ClassSource, object>> source = s => s.ListProp;
+            Expression<Func<ClassDest, object>> target = d => d.ListProp;
+            Tuple<Expression, Expression, bool, string> tuple = Tuple.Create(source.Body, target.Body, true, string.Empty);
+            expected.CheckAndConfigureMappingTest(tuple);
+            Assert.IsNotNull(expected.GetDelegate());
+        }
+
+        [TestMethod, TestCategory("CheckAndConfigureTuple")]
+        public void CheckAndConfigureMappingTest_List_SameType_Success()
+        {
+            ExpressionMapper.Reset();
+            ExpressionMapper.CreateMap<ClassSource2, ClassDest2>();
+
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            MapperConfigurationCollectionContainer.Instance.Add(expected);
+            ExpressionMapper.Initialize();
+            Expression<Func<ClassSource, object>> source = s => s.ListString;
+            Expression<Func<ClassDest, object>> target = d => d.ListString;
+            Tuple<Expression, Expression, bool, string> tuple = Tuple.Create(source.Body, target.Body, false, string.Empty);
+            expected.CheckAndConfigureMappingTest(tuple);
+            Assert.IsNotNull(expected.GetDelegate());
+        }
+    }
+}

+ 191 - 0
Masuit.Tools.UnitTest/Mapping/Core/MapperConfigurationTests.cs

@@ -0,0 +1,191 @@
+using Masuit.Tools.Mapping;
+using Masuit.Tools.Mapping.Core;
+using Masuit.Tools.Mapping.Exceptions;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Masuit.Tools.UnitTest.Mapping.Core
+{
+    [TestClass]
+    public class MapperConfigurationTests
+    {
+
+        [TestMethod, TestCategory("Ignore")]
+        public void Ignore_Add_Succes()
+        {
+            var actual = new MapperConfigurationTestContainer();
+            actual.Ignore((d) => d.PropInt1);
+            Assert.AreEqual(actual.GetIgnoreCount(), 1);
+        }
+        [TestMethod, TestCategory("AfterMap")]
+        public void AfterMap_Add_Succes()
+        {
+            var actual = new MapperConfigurationTestContainer();
+            actual.AfterMap((s, d) =>
+            {
+                //Nothing To Do
+            });
+            Assert.AreEqual(actual.GetAfterMapActionCount(), 1);
+        }
+        [TestMethod, TestCategory("ExecuteAfterActions")]
+        public void ExecuteAfterActions_Succes()
+        {
+            bool excecutedAction = false;
+            var actual = new MapperConfigurationTestContainer();
+            actual.AfterMap((s, d) =>
+            {
+                excecutedAction = true;
+            });
+            actual.ExecuteAfterActions(new ClassSource(), new ClassDest());
+            Assert.IsTrue(excecutedAction);
+        }
+
+
+        [TestMethod, TestCategory("ReverseMap")]
+        public void ReverseMap_Success()
+        {
+            ExpressionMapper.Reset();
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+
+            var actual = expected.ReverseMap();
+
+            Assert.IsInstanceOfType(actual, typeof(MapperConfiguration<ClassDest, ClassSource>));
+        }
+
+        [TestMethod, TestCategory("ReverseMap"), ExpectedException(typeof(MapperExistException))]
+        public void ReverseMap_MapperAlreadyExist_Exception()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            MapperConfiguration<ClassDest, ClassSource> actual = null;
+
+            expected.ReverseMap();
+
+            actual = expected.ReverseMap();
+            MapperConfigurationCollectionContainer.Instance.RemoveAt(1);
+        }
+
+        [TestMethod, TestCategory("Exception"), ExpectedException(typeof(NotSameTypePropertyException))]
+        public void NotSameTypePropertyException_Exception()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.ForMember(s => s.PropInt1, d => d.PropString2);
+            expected.CreateMappingExpression(null);
+        }
+
+        [TestMethod, TestCategory("Exception"), ExpectedException(typeof(ReadOnlyPropertyException))]
+        public void ReadOnlyPropertyExceptionException_Exception()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.ForMember(s => s.PropInt1, d => d.RealOnlyPropInt1);
+            expected.CreateMappingExpression(null);
+        }
+
+        [TestMethod, TestCategory("GetSortedExpression")]
+        public void GetSortedExpression_PropertyFound_Succes()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.CreateMappingExpression(null);
+            var actual = expected.GetSortedExpression("PropInt1");
+            Assert.IsNotNull(actual);
+        }
+
+        [TestMethod, TestCategory("GetSortedExpression"), ExpectedException(typeof(PropertyNoExistException))]
+        public void GetSortedExpression_PropertyNotFound_Exception()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.CreateMappingExpression(null);
+            expected.GetSortedExpression("PropNotExist");
+        }
+
+        [TestMethod, TestCategory("GetMapper"), ExpectedException(typeof(NoFoundMapperException))]
+        public void GetMapper_NoFoundMapperException()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.GetMapperTest(typeof(string), typeof(string), true);
+        }
+
+        [TestMethod, TestCategory("CreateMappingExpression")]
+        public void CreateMappingExpression_NotInitialise()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.CreateMappingExpression(null);
+            int actual = expected.MemberToMapForNew.Count;
+            Assert.IsTrue(actual > 0);
+        }
+
+
+        [TestMethod, TestCategory("GetPropertyInfo")]
+        public void GetPropertyInfo_PropertyFound_Success()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            Expression<Func<ClassSource, object>> exp = x => x.PropInt1;
+            var actual = expected.GetPropertyInfoTest(exp);
+
+            Assert.AreEqual(actual.Name, "PropInt1");
+        }
+        [TestMethod, TestCategory("GetPropertyInfo"), ExpectedException(typeof(NotImplementedException))]
+        public void GetPropertyInfo_PropertyNotImplementedException()
+        {
+            PropertyInfo actual = null;
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            Expression<Func<ClassDest, object>> exp = x => x.PropInt1 > 0;
+            actual = expected.GetPropertyInfoTest(exp);
+        }
+        [TestMethod, TestCategory("GetPropertyInfo"), ExpectedException(typeof(NotImplementedException))]
+        public void GetPropertyInfo_PropertyNotImplementedExceptionDefault()
+        {
+            PropertyInfo actual = null;
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            Expression<Func<ClassDest, object>> exp = x => null;
+
+            actual = expected.GetPropertyInfoTest(exp);
+
+        }
+        [TestMethod, TestCategory("CreateCommonMember")]
+        public void CreateCommonMember_FindMapper_NotList_Success()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            ExpressionMapper.Reset();
+            ExpressionMapper.CreateMap<ClassSource2, ClassDest2>();
+
+            expected.CreateMappingExpression(null);
+            var actual = expected.GetGenericLambdaExpression();
+            ExpressionMapper.Reset();
+
+        }
+        [TestMethod, TestCategory("CreateCommonMember")]
+        public void CreateCommonMember_IgnoreProperty()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.Ignore(d => d.PropInt1);
+            expected.CreateCommonMemberTest();
+        }
+        [TestMethod, TestCategory("CheckAndRemoveMemberDest")]
+        public void CheckAndRemoveMemberDest_PropertyExist_Remove()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            expected.CreateMappingExpression(null);
+
+            int countOri = expected.MemberToMapForNew.Count;
+
+            expected.CheckAndRemoveMemberDestTest("PropInt1");
+            Assert.AreNotEqual(countOri, expected.MemberToMapForNew.Count);
+        }
+
+        [TestMethod, TestCategory("CreateMemberAssignementForExisting")]
+        public void CreateMemberAssignementForExisting_Succes()
+        {
+            MapperConfigurationTestContainer expected = new MapperConfigurationTestContainer();
+            MapperConfigurationCollectionContainer.Instance.Add(expected);
+
+            ExpressionMapper.CreateMap<ClassSource2, ClassDest2>();
+            expected.CreateMappingExpression(null);
+
+            Assert.IsNotNull(expected.GetDelegateForExistingTargetTest());
+        }
+    }
+
+}

+ 37 - 0
Masuit.Tools.UnitTest/Mapping/Core/MapperContainerTest.cs

@@ -0,0 +1,37 @@
+using Masuit.Tools.Mapping.Core;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections;
+
+namespace Masuit.Tools.UnitTest.Mapping.Core
+{
+    [TestClass]
+    public class MapperContainerTest
+    {
+        [TestMethod, TestCategory("MapperContainer")]
+        public void RemotAt_Success()
+        {
+            MapperConfigurationCollectionContainer.Instance.Clear();
+            var countMapper = 0;
+            var mapperToInsert = new MapperConfiguration<ClassSource, ClassDest>("sourceTest");
+            MapperConfigurationCollectionContainer.Instance.Add(mapperToInsert);
+            MapperConfigurationCollectionContainer.Instance.RemoveAt(0);
+            Assert.AreEqual(countMapper, MapperConfigurationCollectionContainer.Instance.Count);
+            MapperConfigurationCollectionContainer.Instance.Clear();
+
+        }
+        [TestMethod, TestCategory("MapperContainer")]
+        public void GetEnumerator_Success()
+        {
+            MapperConfigurationCollectionContainer.Instance.Clear();
+
+            var mapperToInsert = new MapperConfiguration<ClassSource, ClassDest>("sourceTest");
+            MapperConfigurationCollectionContainer.Instance.Add(mapperToInsert);
+            IEnumerator actual = (MapperConfigurationCollectionContainer.Instance as IEnumerable).GetEnumerator();
+            Assert.IsNotNull(actual);
+            Assert.IsTrue(actual.MoveNext());
+            MapperConfigurationCollectionContainer.Instance.Clear();
+
+        }
+    }
+}

+ 85 - 0
Masuit.Tools.UnitTest/Mapping/Core/MapperExpressionVisitorTest.cs

@@ -0,0 +1,85 @@
+using Masuit.Tools.Mapping.Visitor;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.UnitTest.Mapping.Core
+{
+    [TestClass]
+    public class MapperExpressionVisitorTest
+    {
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ExpressionIsNull_ReturnNull()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            Expression exp = null;
+
+            var actual = expected.Visit(exp);
+
+            Assert.IsNull(actual);
+        }
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ExpressionLambdaConstantSimple_ReturnExpression()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            Expression<Func<ClassSource, object>> exp = x => x.PropInt1;
+
+            var actual = expected.Visit(exp, true);
+
+            Assert.IsNotNull(actual);
+        }
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ExpressionConstantSimple_ReturnExpression()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            Expression<Func<ClassSource, object>> exp = x => x.PropInt1;
+
+            var actual = expected.Visit(exp.Body, true);
+
+            Assert.IsNotNull(actual);
+        }
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ExpressionMemberSimple_ReturnExpression()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            Expression<Func<ClassSource, object>> exp = x => x.PropString1;
+
+            var actual = expected.Visit(exp.Body, true);
+
+            Assert.IsNotNull(actual);
+        }
+
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ExpressionSubClassCheckIfNull_ReturnExpression()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            Expression<Func<ClassSource, object>> exp = x => x.SubClass.PropString1;
+
+            var actual = expected.Visit(exp, true);
+
+            Assert.IsTrue(actual.NodeType == ExpressionType.MemberAccess);
+        }
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ExpressionSubClassCheckIfNull_DefaultValueConstant_ReturnExpression()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            Expression<Func<ClassSource, object>> exp = x => x.SubClass.PropInt1;
+
+            var actual = expected.Visit(exp, true);
+
+            Assert.IsTrue(actual.NodeType == ExpressionType.MemberAccess);
+        }
+        [TestMethod, TestCategory("Visit")]
+        public void Visit_ParameterExpression_CheckIfNull_IsTrue_Expression()
+        {
+            MapperExpressionVisitor expected = new MapperExpressionVisitor(Expression.Parameter(typeof(ClassSource), "s"));
+            ParameterExpression exp = Expression.Parameter(typeof(ClassSource2), "x");
+
+            Expression actual = expected.Visit(exp, true) as ParameterExpression;
+
+            Assert.IsTrue(actual.NodeType == ExpressionType.Parameter);
+            Assert.AreNotEqual(actual.Type, exp.Type);
+        }
+    }
+}

+ 57 - 0
Masuit.Tools.UnitTest/Mapping/Extentions/MapperExtentionsTest.cs

@@ -0,0 +1,57 @@
+using Masuit.Tools.Mapping;
+using Masuit.Tools.Mapping.Extensions;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.UnitTest.Mapping.Extentions
+{
+    [TestClass]
+    public class MapperExtentionsTest
+    {
+        [ClassInitialize]
+        public static void Init(TestContext context)
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2).ReverseMap();
+            ExpressionMapper.CreateMap<ClassDest2, ClassSource2>().ForMember(s => s.PropString2, d => d.PropString1).ReverseMap();
+            ExpressionMapper.Initialize();
+        }
+
+        [ClassCleanup]
+        public static void Clean()
+        {
+            ExpressionMapper.Reset();
+        }
+
+        [TestMethod]
+        public void ConvertTo_SimpleExpression_Success()
+        {
+            Expression<Func<ClassDest, bool>> expected = x => x.PropString2 == "test";
+
+            var actual = expected.ConvertTo<ClassDest, ClassSource>() as LambdaExpression;
+            var test = actual.Body as BinaryExpression;
+            Assert.IsNotNull(actual);
+            Assert.IsInstanceOfType(test.Left, typeof(MemberExpression));
+            Assert.AreEqual((test.Left as MemberExpression).Member.ReflectedType, typeof(ClassSource));
+            Assert.AreEqual((test.Left as MemberExpression).Member.Name, "PropString1");
+        }
+
+        [TestMethod]
+        public void ConvertTo_WithType()
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2).ReverseMap();
+            Expression<Func<ClassDest, bool>> expected = x => x.PropString2 == "test";
+
+            var actual = expected.ConvertTo(typeof(ClassSource)) as LambdaExpression;
+            var test = actual.Body as BinaryExpression;
+
+            Assert.IsNotNull(actual);
+            Assert.IsInstanceOfType(test.Left, typeof(MemberExpression));
+            Assert.AreEqual((test.Left as MemberExpression).Member.ReflectedType, typeof(ClassSource));
+            Assert.AreEqual((test.Left as MemberExpression).Member.Name, "PropString1");
+        }
+    }
+}

+ 101 - 0
Masuit.Tools.UnitTest/Mapping/Extentions/QueryableExtentionsTest.cs

@@ -0,0 +1,101 @@
+using Masuit.Tools.Mapping;
+using Masuit.Tools.Mapping.Extensions;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.UnitTest.Mapping.Extentions
+{
+    [TestClass]
+    public class QueryableExtentionsTest
+    {
+        [ClassInitialize]
+        public static void Init(TestContext context)
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2).ReverseMap();
+            ExpressionMapper.Initialize();
+        }
+
+        [ClassCleanup]
+        public static void Clean()
+        {
+            ExpressionMapper.Reset();
+        }
+
+        [TestMethod, TestCategory("Extentions")]
+        public void OrderBy_Success()
+        {
+            Init(null);
+
+            QueryableImplTest<ClassSource> expected = new QueryableImplTest<ClassSource>();
+
+            IQueryable<ClassSource> actual = expected.OrderBy<ClassSource, ClassDest>("PropInt1");
+            Assert.IsTrue(CheckExpressionMethod(actual.Expression, nameof(QueryableExtentions.OrderBy)));
+        }
+
+        [TestMethod, TestCategory("Extentions")]
+        public void OrderByDescending_Success()
+        {
+            QueryableImplTest<ClassSource> expected = new QueryableImplTest<ClassSource>();
+
+            IQueryable<ClassSource> actual = expected.OrderByDescending<ClassSource, ClassDest>("PropInt1");
+            Assert.IsTrue(CheckExpressionMethod(actual.Expression, nameof(QueryableExtentions.OrderByDescending)));
+        }
+
+        [TestMethod, TestCategory("Extentions")]
+        public void ThenBy_Success()
+        {
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2);
+            ExpressionMapper.Initialize();
+
+            QueryableImplTest<ClassSource> expected = new QueryableImplTest<ClassSource>();
+
+            IQueryable<ClassSource> actual = expected.OrderByDescending<ClassSource, ClassDest>("PropInt1").ThenBy<ClassSource, ClassDest>("PropInt1");
+            Assert.IsTrue(CheckExpressionMethod(actual.Expression, nameof(QueryableExtentions.ThenBy)));
+        }
+
+        [TestMethod, TestCategory("Extentions")]
+        public void ThenByDescending_Success()
+        {
+            Init(null);
+
+            QueryableImplTest<ClassSource> expected = new QueryableImplTest<ClassSource>();
+
+            IQueryable<ClassSource> actual = expected.OrderByDescending<ClassSource, ClassDest>("PropInt1").ThenByDescending<ClassSource, ClassDest>("PropInt1");
+            Assert.IsTrue(CheckExpressionMethod(actual.Expression, nameof(QueryableExtentions.ThenByDescending)));
+        }
+
+        [TestMethod, TestCategory("Extentions")]
+        public void Select_Success()
+        {
+            Init(null);
+
+            QueryableImplTest<ClassSource> expected = new QueryableImplTest<ClassSource>();
+
+            var actual = expected.Select<ClassSource, ClassDest>();
+            Assert.IsTrue(CheckExpressionMethod(actual.Expression, nameof(QueryableExtentions.Select)));
+        }
+
+        [TestMethod, TestCategory("Extentions")]
+        public void Where_Success()
+        {
+            QueryableImplTest<ClassDest> expected = new QueryableImplTest<ClassDest>();
+            Expression<Func<ClassSource, bool>> criterias = x => x.PropInt1 == 1;
+            var actual = expected.Where(criterias);
+            Assert.IsTrue(CheckExpressionMethod(actual.Expression, nameof(QueryableExtentions.Where)));
+        }
+
+        private bool CheckExpressionMethod(Expression expression, string methodeName)
+        {
+            if (expression.NodeType == ExpressionType.Call)
+            {
+                return (expression as MethodCallExpression).Method.Name == methodeName;
+            }
+
+            return false;
+        }
+    }
+}

+ 115 - 0
Masuit.Tools.UnitTest/Mapping/MapperTests.cs

@@ -0,0 +1,115 @@
+using Masuit.Tools.Mapping;
+using Masuit.Tools.Mapping.Core;
+using Masuit.Tools.Mapping.Exceptions;
+using Masuit.Tools.UnitTest.Mapping.ClassTests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Masuit.Tools.UnitTest.Mapping
+{
+    [TestClass]
+    public class MapperTests
+    {
+        [ClassInitialize]
+        public static void Init(TestContext context)
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2);
+        }
+
+        [ClassCleanup]
+        public static void Clean()
+        {
+            ExpressionMapper.Reset();
+        }
+
+        [TestMethod, TestCategory("CreateMap")]
+        public void Mapper_CreateMap_NotExist_ContainerCount1()
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2);
+
+            Assert.AreEqual(MapperConfigurationCollectionContainer.Instance.Count, 1);
+        }
+
+        [TestMethod, TestCategory("CreateMap")]
+        public void Mapper_CreateMap_Already_Exist_ContainerCount1()
+        {
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>();
+
+            Assert.IsTrue(MapperConfigurationCollectionContainer.Instance.Exists(m => m.SourceType == typeof(ClassSource) && m.TargetType == typeof(ClassDest)));
+        }
+
+        [TestMethod, TestCategory("CreateMap")]
+        public void Mapper_CreateMap_With_Name()
+        {
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>("test");
+            Assert.IsTrue(MapperConfigurationCollectionContainer.Instance.Exists(m => m.Name == "test"));
+        }
+
+        [TestMethod, TestCategory("Map")]
+        public void Map_ReturnDestinationObject_Success()
+        {
+            ExpressionMapper.Initialize();
+
+            ClassSource expected = new ClassSource()
+            {
+                PropInt1 = 1,
+                PropSourceInt1 = 1,
+                PropString1 = "test"
+            };
+
+            var actual = expected.Map<ClassSource, ClassDest>();
+
+            Assert.AreEqual(actual.PropInt1, expected.PropInt1);
+            Assert.AreEqual(actual.PropString2, expected.PropString1);
+            Assert.AreEqual(actual.PropInt2, 0);
+        }
+
+        [TestMethod, TestCategory("GetQueryExpression")]
+        public void GetQueryExpression_ReturnExpression()
+        {
+            Clean();
+            ExpressionMapper.CreateMap<ClassSource, ClassDest>().ForMember(s => s.PropString1, d => d.PropString2);
+            ExpressionMapper.Initialize();
+
+            var actual = ExpressionMapper.GetQueryExpression<ClassSource, ClassDest>();
+
+            Assert.IsNotNull(actual);
+        }
+
+        [TestMethod, TestCategory("GetQuery")]
+        public void GetQuery_ReturnFunc()
+        {
+            Init(null);
+            ExpressionMapper.Initialize();
+
+            var actual = ExpressionMapper.GetQuery<ClassSource, ClassDest>();
+
+            Assert.IsNotNull(actual);
+        }
+
+        [TestMethod, TestCategory("Exception"), ExpectedException(typeof(NoFoundMapperException))]
+        public void Map_NoFoundMapperException_Exception()
+        {
+            new ClassSource().Map<ClassSource, ClassDest2>();
+        }
+
+        [TestMethod, TestCategory("Exception"), ExpectedException(typeof(NoActionAfterMappingException))]
+        public void Map_NoActionException_Exception()
+        {
+            ExpressionMapper.GetMapper<ClassSource, ClassDest>().AfterMap(null);
+            ExpressionMapper.Initialize();
+            new ClassSource().Map<ClassSource, ClassDest>();
+            Clean();
+        }
+
+        [TestMethod]
+        public void GetPropertiesNotMapped_ReturnProperties_Success()
+        {
+            ExpressionMapper.Initialize();
+            var actual = ExpressionMapper.GetPropertiesNotMapped<ClassSource, ClassDest>();
+            Assert.IsTrue(actual.SourceProperties.Count > 0);
+            Assert.IsTrue(actual.TargetProperties.Count > 0);
+        }
+    }
+}

+ 15 - 1
Masuit.Tools.UnitTest/Masuit.Tools.UnitTest.csproj

@@ -106,10 +106,24 @@
     <Compile Include="ChineseCalendarTest.cs" />
     <Compile Include="ClassHelperTest.cs" />
     <Compile Include="CompressTest.cs" />
-    <Compile Include="ExpressionGenericMapperTest.cs" />
     <Compile Include="ExtensionMethodsTest.cs" />
     <Compile Include="HtmlToolsTest.cs" />
     <Compile Include="LinqExtensionTest.cs" />
+    <Compile Include="Mapping\ClassTests\ClassDest.cs" />
+    <Compile Include="Mapping\ClassTests\ClassDest2.cs" />
+    <Compile Include="Mapping\ClassTests\ClassSource.cs" />
+    <Compile Include="Mapping\ClassTests\ClassSource2.cs" />
+    <Compile Include="Mapping\ClassTests\IClassDest2.cs" />
+    <Compile Include="Mapping\ClassTests\MapperConfigurationTestContainer.cs" />
+    <Compile Include="Mapping\ClassTests\QueryableImplTest.cs" />
+    <Compile Include="Mapping\Core\ConverterExpressionVisitorTest.cs" />
+    <Compile Include="Mapping\Core\MapperConfigurationBaseTests.cs" />
+    <Compile Include="Mapping\Core\MapperConfigurationTests.cs" />
+    <Compile Include="Mapping\Core\MapperContainerTest.cs" />
+    <Compile Include="Mapping\Core\MapperExpressionVisitorTest.cs" />
+    <Compile Include="Mapping\Extentions\MapperExtentionsTest.cs" />
+    <Compile Include="Mapping\Extentions\QueryableExtentionsTest.cs" />
+    <Compile Include="Mapping\MapperTests.cs" />
     <Compile Include="Mvc\BaseTests.cs" />
     <Compile Include="Mvc\Mocks\MockHttpFilesCollection.cs" />
     <Compile Include="Mvc\Mocks\MockHttpPostedFileBase.cs" />

+ 7 - 11
Masuit.Tools/Files/SevenZipCompressor.cs

@@ -5,6 +5,7 @@ using SharpCompress.Common;
 using SharpCompress.Readers;
 using SharpCompress.Writers;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
@@ -170,15 +171,7 @@ namespace Masuit.Tools.Files
 
             if (remoteUrls.Any())
             {
-                //var dicList = remoteUrls.GroupBy(u => u.Authority).Select(g =>
-                //{
-                //    if (g.Count() > 1)
-                //    {
-                //        string pathname = new string(g.First().AbsolutePath.Substring(0, g.Min(s => s.AbsolutePath.Length)).TakeWhile((c, i) => g.All(s => s.AbsolutePath[i] == c)).ToArray());
-                //        return g.ToDictionary(s => s, s => HttpUtility.UrlDecode(s.AbsolutePath.Substring(pathname.Length)));
-                //    }
-                //    return g.ToDictionary(s => s, s => Path.GetFileName(HttpUtility.UrlDecode(s.AbsolutePath)));
-                //}).SelectMany(d => d).ToDictionary(x => x.Key, x => x.Value);
+                var streams = new ConcurrentDictionary<string, Stream>();
                 using (var httpClient = new HttpClient())
                 {
                     Parallel.ForEach(remoteUrls, url =>
@@ -191,13 +184,16 @@ namespace Masuit.Tools.Files
                                 if (res.IsSuccessStatusCode)
                                 {
                                     Stream stream = await res.Content.ReadAsStreamAsync();
-                                    //archive.AddEntry(Path.Combine(rootdir, pathDic[new Uri(url).AbsolutePath.Trim('/')]), stream);
-                                    archive.AddEntry(Path.Combine(rootdir, Path.GetFileName(HttpUtility.UrlDecode(url.AbsolutePath))), stream);
+                                    streams[Path.Combine(rootdir, Path.GetFileName(HttpUtility.UrlDecode(url.AbsolutePath)))] = stream;
                                 }
                             }
                         }).Wait();
                     });
                 }
+                foreach (var kv in streams)
+                {
+                    archive.AddEntry(kv.Key, kv.Value);
+                }
             }
 
             return archive;

+ 70 - 0
Masuit.Tools/Mapping/Copier.cs

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping
+{
+    public static class Copier<T>
+    {
+        private static readonly ParameterExpression ParameterExpression = Expression.Parameter(typeof(T), "p");
+        private static Func<T, T> _func;
+        private static readonly Dictionary<string, Expression> DictRule = new Dictionary<string, Expression>();
+
+        /// <summary>
+        /// 深拷贝
+        /// </summary>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static T Copy(T source)
+        {
+            if (_func == null)
+            {
+                List<MemberBinding> memberBindings = new List<MemberBinding>();
+                foreach (var item in typeof(T).GetProperties())
+                {
+                    if (DictRule.ContainsKey(item.Name))
+                    {
+                        MemberBinding memberBinding = Expression.Bind(item, DictRule[item.Name]);
+                        memberBindings.Add(memberBinding);
+                    }
+                    else
+                    {
+                        var tInProperty = typeof(T).GetProperty(item.Name);
+                        var tInField = typeof(T).GetField(item.Name);
+                        if (tInProperty != null || tInField != null)
+                        {
+                            MemberExpression property = Expression.PropertyOrField(ParameterExpression, item.Name);
+                            MemberBinding memberBinding = Expression.Bind(item, property);
+                            memberBindings.Add(memberBinding);
+                        }
+                    }
+                }
+
+                foreach (var item in typeof(T).GetFields())
+                {
+                    if (DictRule.ContainsKey(item.Name))
+                    {
+                        MemberBinding memberBinding = Expression.Bind(item, DictRule[item.Name]);
+                        memberBindings.Add(memberBinding);
+                    }
+                    else
+                    {
+                        var tInProperty = typeof(T).GetProperty(item.Name);
+                        var tInField = typeof(T).GetField(item.Name);
+                        if (tInProperty != null || tInField != null)
+                        {
+                            MemberExpression property = Expression.PropertyOrField(ParameterExpression, item.Name);
+                            MemberBinding memberBinding = Expression.Bind(item, property);
+                            memberBindings.Add(memberBinding);
+                        }
+                    }
+                }
+
+                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(T)), memberBindings.ToArray());
+                Expression<Func<T, T>> lambda = Expression.Lambda<Func<T, T>>(memberInitExpression, ParameterExpression);
+                _func = lambda.Compile();
+            }
+            return _func.Invoke(source);
+        }
+    }
+}

+ 12 - 0
Masuit.Tools/Mapping/Core/CreateConfig.cs

@@ -0,0 +1,12 @@
+namespace Masuit.Tools.Mapping.Core
+{
+    /// <summary>
+    /// 映射配置对象
+    /// </summary>
+    internal class CreateConfig
+    {
+        public bool CanCreate { get; set; }
+
+        public string MapperName { get; set; }
+    }
+}

+ 193 - 0
Masuit.Tools/Mapping/Core/MapperConfiguration.cs

@@ -0,0 +1,193 @@
+using Masuit.Tools.Mapping.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Masuit.Tools.Mapping.Core
+{
+    /// <summary>
+    /// 主映射器
+    /// </summary>
+    /// <typeparam name="TSource">源类型</typeparam>
+    /// <typeparam name="TDest">目标类型</typeparam>
+    public class MapperConfiguration<TSource, TDest> : MapperConfigurationBase
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        protected readonly IList<Action<TSource, TDest>> actionsAfterMap;
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public MapperConfiguration(string paramName, string mapperName = null) : base(typeof(TSource), typeof(TDest), paramName, mapperName)
+        {
+            actionsAfterMap = new List<Action<TSource, TDest>>();
+        }
+
+        /// <summary>
+        /// 获取Lambda表达式树
+        /// </summary>
+        /// <returns></returns>
+        public Expression<Func<TSource, TDest>> GetLambdaExpression()
+        {
+            MemberInitExpression exp = GetMemberInitExpression();
+            return Expression.Lambda<Func<TSource, TDest>>(exp, paramClassSource);
+        }
+
+        /// <summary>
+        /// 获取委托
+        /// </summary>
+        /// <returns></returns>
+        public Func<TSource, TDest> GetFuncDelegate()
+        {
+            return (Func<TSource, TDest>)GetDelegate();
+        }
+
+        /// <summary>
+        /// 映射成员
+        /// </summary>
+        /// <param name="getPropertySource">源类型</param>
+        /// <param name="getPropertyDest">目标类型</param>
+        /// <returns></returns>
+        public MapperConfiguration<TSource, TDest> ForMember<TPropertySource, TPropertyDest>(Expression<Func<TSource, TPropertySource>> getPropertySource, Expression<Func<TDest, TPropertyDest>> getPropertyDest)
+        {
+            // 添加到映射列表并且可以继续操作
+            ForMemberBase(getPropertySource.Body, getPropertyDest.Body, false);
+            return this;
+        }
+
+        /// <summary>
+        /// 映射成员
+        /// </summary>
+        /// <typeparam name="TPropertySource">属性源类型</typeparam>
+        /// <typeparam name="TPropertyDest">属性目标类型</typeparam>
+        /// <param name="getPropertySource">源类型</param>
+        /// <param name="getPropertyDest">目标类型</param>
+        /// <param name="checkIfNull">是否检查null值</param>
+        /// <returns></returns>
+        public MapperConfiguration<TSource, TDest> ForMember<TPropertySource, TPropertyDest>(Expression<Func<TSource, TPropertySource>> getPropertySource, Expression<Func<TDest, TPropertyDest>> getPropertyDest, bool checkIfNull)
+        {
+            // 添加到映射列表并且可以继续操作
+            ForMemberBase(getPropertySource.Body, getPropertyDest.Body, checkIfNull);
+            return this;
+        }
+
+        /// <summary>
+        /// 映射成员
+        /// </summary>
+        /// <typeparam name="TPropertySource">属性源类型</typeparam>
+        /// <typeparam name="TPropertyDest">属性目标类型</typeparam>
+        /// <param name="getPropertySource">源类型</param>
+        /// <param name="getPropertyDest">目标类型</param>
+        /// <param name="mapperName">mapper别名</param>
+        /// <returns></returns>
+        public MapperConfiguration<TSource, TDest> ForMember<TPropertySource, TPropertyDest>(Expression<Func<TSource, TPropertySource>> getPropertySource, Expression<Func<TDest, TPropertyDest>> getPropertyDest, string mapperName)
+        {
+            // 添加到映射列表并且可以继续操作
+            ForMemberBase(getPropertySource.Body, getPropertyDest.Body, true, mapperName);
+            return this;
+        }
+
+        /// <summary>
+        /// 忽略一些不需要映射的成员
+        /// </summary>
+        /// <param name="propertyDest">属性名</param>
+        /// <returns></returns>
+        public MapperConfiguration<TSource, TDest> Ignore<TProperty>(Expression<Func<TDest, TProperty>> propertyDest)
+        {
+            return IgnoreBase(propertyDest) as MapperConfiguration<TSource, TDest>;
+        }
+
+        /// <summary>
+        /// 映射后要执行的操作
+        /// </summary>
+        /// <param name="actionAfterMap">映射后要执行的操作</param>
+        /// <returns></returns>
+        public MapperConfiguration<TSource, TDest> AfterMap(Action<TSource, TDest> actionAfterMap)
+        {
+            // 添加到映射列表并且可以继续操作
+            actionsAfterMap.Add(actionAfterMap);
+            return this;
+        }
+
+        /// <summary>
+        /// 执行后续操作。
+        /// </summary>
+        /// <param name="source">源类型</param>
+        /// <param name="dest">目标类型</param>
+        public void ExecuteAfterActions(TSource source, TDest dest)
+        {
+            if (actionsAfterMap.Count > 0)
+            {
+                foreach (var action in actionsAfterMap)
+                {
+                    if (action == null)
+                    {
+                        throw new NoActionAfterMappingException();
+                    }
+                    action(source, dest);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 反向映射
+        /// </summary>
+        /// <param name="name">mapper别名</param>
+        /// <returns>
+        /// 新的mapper对象
+        /// </returns>
+        /// <exception cref="MapperExistException"></exception>
+        public MapperConfiguration<TDest, TSource> ReverseMap(string name = null)
+        {
+            MapperConfigurationBase map = GetMapper(typeof(TDest), typeof(TSource), false, name);
+
+            if (map != null)
+            {
+                throw new MapperExistException(typeof(TDest), typeof(TSource));
+            }
+            string finalName = string.IsNullOrEmpty(name) ? "s" + (MapperConfigurationCollectionContainer.Instance.Count).ToString() : name;
+            map = new MapperConfiguration<TDest, TSource>(finalName);
+            MapperConfigurationCollectionContainer.Instance.Add(map);
+            CreateCommonMember();
+
+            // 现有属性的映射,并且创建反向关系
+            foreach (var item in PropertiesMapping)
+            {
+                PropertyInfo propertyDest = GetPropertyInfo(item.Item1);
+                if (propertyDest.CanWrite)
+                {
+                    if (!string.IsNullOrEmpty(item.Item4))
+                    {
+                        //找到反向关系的mapper
+                        var reverseMapper = GetMapper(item.Item2.Type, item.Item1.Type, false);
+                        if (reverseMapper != null)
+                        {
+                            map.ForMemberBase(item.Item2, item.Item1, item.Item3, reverseMapper.Name);
+                        }
+                    }
+                    else
+                    {
+                        if (item.Item1.NodeType == ExpressionType.MemberAccess)
+                        {
+                            map.ForMemberBase(item.Item2, item.Item1, item.Item3, item.Item4);
+                        }
+                    }
+                }
+            }
+
+            return (MapperConfiguration<TDest, TSource>)map;
+        }
+
+        /// <summary>
+        /// 是否使用服务注入
+        /// </summary>
+        public MapperConfiguration<TSource, TDest> ConstructUsingServiceLocator()
+        {
+            UseServiceLocator = true;
+            return this;
+        }
+    }
+}

+ 667 - 0
Masuit.Tools/Mapping/Core/MapperConfigurationBase.cs

@@ -0,0 +1,667 @@
+using Masuit.Tools.Mapping.Exceptions;
+using Masuit.Tools.Mapping.Helper;
+using Masuit.Tools.Mapping.Visitor;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Masuit.Tools.Mapping.Core
+{
+    /// <summary>
+    /// mapper配置基类
+    /// </summary>
+    public abstract class MapperConfigurationBase
+    {
+        private Delegate _delegateCallForNew;
+
+        private Delegate _delegateCallForExisting;
+
+        private Func<Type, object> _constructorFunc;
+
+        private bool _isInitialized;
+        private readonly MethodInfo _selectMethod;
+
+        private readonly MethodInfo _toListMethod;
+
+        private readonly List<PropertyInfo> _propertiesToIgnore;
+
+        internal ParameterExpression paramClassSource;
+        internal MapperExpressionVisitor visitorMapper;
+        internal List<MemberAssignment> memberForNew;
+        internal LambdaExpression expressionForExisting;
+
+        /// <summary>
+        /// 属性映射对应关系<br/>
+        /// Item1 : 源表达式<br/>
+        /// Item2 : 目标表达式<br/>
+        /// Item3 : 检查null值<br/>
+        /// Item4 : mapper别名<br/>
+        /// </summary>
+        protected List<Tuple<Expression, Expression, bool, string>> PropertiesMapping { get; private set; }
+
+
+        /// <summary>
+        /// 需要被忽略映射的属性
+        /// </summary>
+        protected ReadOnlyCollection<PropertyInfo> PropertiesToIgnore => _propertiesToIgnore.AsReadOnly();
+
+        /// <summary>
+        /// 是否使用服务依赖注入
+        /// </summary>
+        public bool UseServiceLocator { get; protected set; }
+
+        /// <summary>
+        /// 对象源类型
+        /// </summary>
+        public Type SourceType { get; private set; }
+
+        /// <summary>
+        /// 对象目标类型
+        /// </summary>
+        public Type TargetType { get; private set; }
+
+        /// <summary>
+        /// 获取mapper映射成员
+        /// </summary>
+        public ReadOnlyCollection<MemberAssignment> MemberToMapForNew => new ReadOnlyCollection<MemberAssignment>(memberForNew);
+
+
+        /// <summary>
+        /// mapper别名
+        /// </summary>
+        public string Name { get; protected set; }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="source">源类型</param>
+        /// <param name="destination">目标类型</param>
+        /// <param name="paramName">属性名</param>
+        /// <param name="name">别名</param>
+        protected MapperConfigurationBase(Type source, Type destination, string paramName, string name = null)
+        {
+            TargetType = destination;
+            SourceType = source;
+            paramClassSource = Expression.Parameter(source, paramName);
+            Name = string.IsNullOrEmpty(name) ? paramName : name;
+            _propertiesToIgnore = new List<PropertyInfo>();
+            PropertiesMapping = new List<Tuple<Expression, Expression, bool, string>>();
+            visitorMapper = new MapperExpressionVisitor(paramClassSource);
+            memberForNew = new List<MemberAssignment>();
+            _selectMethod = typeof(Enumerable).GetMethods().Where(m => m.Name == "Select").Select(x => x.GetParameters().First(p => p.Name.Equals("selector") && p.ParameterType.GetGenericArguments().Length == 2)).First().Member as MethodInfo;
+            _toListMethod = typeof(Enumerable).GetMethod("ToList");
+        }
+
+        /// <summary>
+        /// 获取mapper委托
+        /// </summary>
+        /// <returns></returns>
+        public Delegate GetDelegate()
+        {
+            if (!_isInitialized)
+            {
+                throw new MapperNotInitializedException(SourceType, TargetType);
+            }
+
+            // 因为在这里有映射器的性能问题,而缓存委托会显着缩短处理时间,如果没有表达式编译每次编译会很慢
+            if (_delegateCallForNew == null)
+            {
+                MemberInitExpression exp = GetMemberInitExpression();
+
+                _delegateCallForNew = Expression.Lambda(exp, paramClassSource).Compile();
+            }
+
+            return _delegateCallForNew;
+        }
+
+        /// <summary>
+        /// 获取现有目标类型的委托。
+        /// </summary>
+        /// <exception cref="MapperNotInitializedException"></exception>
+        public Delegate GetDelegateForExistingTarget()
+        {
+            if (!_isInitialized)
+            {
+                throw new MapperNotInitializedException(SourceType, TargetType);
+            }
+
+            // 因为在这里有映射器的性能问题,而缓存委托会显着缩短处理时间,如果没有表达式编译每次编译会很慢
+            if (_delegateCallForExisting == null)
+            {
+                CreateMemberAssignementForExistingTarget();
+            }
+
+            return _delegateCallForExisting;
+        }
+
+        /// <summary>
+        /// 获取泛型的Lambda表达式
+        /// </summary>
+        public LambdaExpression GetGenericLambdaExpression()
+        {
+            MemberInitExpression exp = GetMemberInitExpression();
+            return Expression.Lambda(exp, paramClassSource);
+        }
+
+        /// <summary>
+        /// 获取目标类型的实际类型
+        /// </summary>
+        public Type GetDestinationType()
+        {
+            return GetRealType(TargetType);
+        }
+
+        /// <summary>
+        /// 忽略目标类型的属性
+        /// </summary>
+        /// <typeparam name="TDest">对象源类型</typeparam>
+        /// <typeparam name="TProperty">对象目标类型</typeparam>
+        /// <param name="propertyDest">目标对象的属性</param>
+        /// <returns></returns>
+        protected MapperConfigurationBase IgnoreBase<TDest, TProperty>(Expression<Func<TDest, TProperty>> propertyDest)
+        {
+            // 添加到映射列表并且可以继续操作
+            _propertiesToIgnore.Add(GetPropertyInfo(propertyDest));
+            return this;
+        }
+
+        /// <summary>
+        /// 获取映射器实例
+        /// </summary>
+        /// <param name="typeOfSource">源类型</param>
+        /// <param name="typeOfTarget">目标类型</param>
+        /// <param name="throwExceptionOnNoFound">如果没找到是否需要抛出异常</param>
+        /// <param name="name">mapper别名</param>
+        /// <returns></returns>
+        /// <exception cref="NoFoundMapperException"></exception>
+        protected static MapperConfigurationBase GetMapper(Type typeOfSource, Type typeOfTarget, bool throwExceptionOnNoFound, string name = null)
+        {
+            var mapperExterne = MapperConfigurationCollectionContainer.Instance.Find(typeOfSource, typeOfTarget, name);
+            // 如果没有任何配置,手动抛出异常
+            if (mapperExterne == null && throwExceptionOnNoFound)
+            {
+                throw new NoFoundMapperException(typeOfSource, typeOfTarget);
+            }
+
+            return mapperExterne;
+        }
+
+        /// <summary>
+        /// 创建公共成员
+        /// </summary>
+        protected void CreateCommonMember()
+        {
+            PropertyInfo[] propertiesSource = SourceType.GetProperties();
+            foreach (PropertyInfo propSource in propertiesSource)
+            {
+                PropertyInfo propDest = TargetType.GetProperty(propSource.Name);
+                if (propDest != null)
+                {
+                    // 检查是否已存在或被忽略。
+                    bool ignorePropDest = _propertiesToIgnore.Exists(x => x.Name == propDest.Name) || PropertiesMapping.Exists(x => GetPropertyInfo(x.Item2).Name == propDest.Name);
+
+                    if (propDest.CanWrite && !ignorePropDest)
+                    {
+                        Type sourceType = propSource.PropertyType;
+                        Type destType = propDest.PropertyType;
+                        bool isList = IsListOf(destType);
+                        if (isList)
+                        {
+                            sourceType = TypeSystem.GetElementType(propSource.PropertyType);
+                            destType = TypeSystem.GetElementType(propDest.PropertyType);
+                        }
+
+                        var canCreateConfig = CanCreateConfig(sourceType, destType);
+                        if (canCreateConfig.CanCreate)
+                        {
+                            // 只创造现有的关系
+                            Expression expSource = Expression.MakeMemberAccess(paramClassSource, propSource);
+                            ParameterExpression paramDest = Expression.Parameter(TargetType, "t");
+                            Expression expDest = Expression.MakeMemberAccess(paramDest, propDest);
+                            PropertiesMapping.Add(Tuple.Create(expSource, expDest, false, canCreateConfig.MapperName));
+                        }
+                    }
+                }
+            }
+        }
+
+        private static CreateConfig CanCreateConfig(Type typeSource, Type typeTarget)
+        {
+            CreateConfig result = new CreateConfig
+            {
+                CanCreate = typeSource == typeTarget
+            };
+            //不是同一类型
+            if (!result.CanCreate)
+            {
+                //查找是否存在映射器
+                var mapper = MapperConfigurationCollectionContainer.Instance.Find(typeSource, typeTarget);
+                if (mapper != null)
+                {
+                    result.MapperName = mapper.Name;
+                    result.CanCreate = true;
+                }
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// 检查并配置mapper
+        /// </summary>
+        /// <param name="configExpression">配置表达式树</param>
+        /// <exception cref="NotSameTypePropertyException">
+        /// </exception>
+        /// <exception cref="ReadOnlyPropertyException"></exception>
+        protected void CheckAndConfigureMapping(ref Tuple<Expression, Expression, bool, string> configExpression)
+        {
+            Type typeSource = configExpression.Item1.Type;
+            Type typeTarget = configExpression.Item2.Type;
+
+            // 正常情况下,目标表达式是一个成员表达式树
+            PropertyInfo propTarget = GetPropertyInfo(configExpression.Item2);
+
+            if (propTarget.CanWrite)
+            {
+                CheckAndRemoveMemberDest(propTarget.Name);
+                if (!IsListOf(typeTarget))
+                {
+                    CreatBindingFromSimple(ref configExpression, typeSource, typeTarget, propTarget);
+                }
+                else
+                {
+                    CreateBindingFromList(ref configExpression, typeSource, typeTarget, propTarget);
+                }
+            }
+            else
+            {
+                throw new ReadOnlyPropertyException(propTarget);
+            }
+        }
+
+        /// <summary>
+        /// 检查并移除目标成员
+        /// </summary>
+        /// <param name="properyName">属性名</param>
+        protected void CheckAndRemoveMemberDest(string properyName)
+        {
+            Predicate<MemberAssignment> exp = m => m.Member.Name == properyName;
+            if (memberForNew.Exists(exp))
+            {
+                memberForNew.RemoveAll(exp);
+            }
+        }
+
+        /// <summary>
+        /// 获取成员初始化表达式。
+        /// </summary>
+        /// <returns></returns>
+        protected MemberInitExpression GetMemberInitExpression()
+        {
+            Type typeDest = GetDestinationType();
+            NewExpression newClassDest = Expression.New(typeDest);
+            MemberInitExpression exp = Expression.MemberInit(newClassDest, MemberToMapForNew);
+            return exp;
+        }
+
+        /// <summary>
+        /// 创建成员绑定。
+        /// </summary>
+        /// <param name="propertyExpression">属性表达式</param>
+        /// <param name="propertyTarget">目标属性</param>
+        /// <param name="checkIfNull">是否检查null值</param>
+        protected void CreateMemberBinding(Expression propertyExpression, MemberInfo propertyTarget, bool checkIfNull)
+        {
+            // 访问表达式进行转换
+            Expression result = visitorMapper.Visit(propertyExpression, checkIfNull);
+            MemberAssignment bind = Expression.Bind(propertyTarget, result);
+            memberForNew.Add(bind);
+        }
+
+        /// <summary>
+        /// 将表达式源的映射分配给属性目标。
+        /// </summary>
+        /// <param name="getPropertySource">属性源类型</param>
+        /// <param name="getPropertyDest">属性目标类型</param>
+        /// <param name="checkIfNull">是否检查null值</param>
+        /// <param name="name">要使用的映射器的别名</param>
+        internal MapperConfigurationBase ForMemberBase(Expression getPropertySource, Expression getPropertyDest, bool checkIfNull, string name = null)
+        {
+            // 添加到映射列表并且可以继续操作
+            PropertiesMapping.Add(Tuple.Create(getPropertySource, getPropertyDest, checkIfNull, name));
+            return this;
+        }
+
+        /// <summary>
+        /// 获取属性信息。
+        /// </summary>
+        /// <param name="propertyExpression">属性表达式树</param>
+        /// <returns></returns>
+        /// <exception cref="System.NotImplementedException">
+        /// 这种表达方式不承担职责,或者这种类型的表达式是无效的
+        /// </exception>
+        protected static PropertyInfo GetPropertyInfo(Expression propertyExpression)
+        {
+            var expressionToAnalyse = propertyExpression.NodeType == ExpressionType.Lambda ? (propertyExpression as LambdaExpression).Body : propertyExpression;
+            switch (expressionToAnalyse.NodeType)
+            {
+                case ExpressionType.Convert:
+                    Expression operand = (expressionToAnalyse as UnaryExpression).Operand;
+                    switch (operand.NodeType)
+                    {
+                        case ExpressionType.MemberAccess:
+                            return (operand as MemberExpression).Member as PropertyInfo;
+                        default:
+                            throw new NotImplementedException("这种表达方式目前尚未支持");
+                    }
+                case ExpressionType.MemberAccess:
+                    return (expressionToAnalyse as MemberExpression).Member as PropertyInfo;
+                default:
+                    throw new NotImplementedException("这种表达方式目前尚未支持");
+            }
+        }
+
+        internal void Initialize(Func<Type, object> constructor)
+        {
+            CreateMappingExpression(constructor);
+            CreateMemberAssignementForExistingTarget();
+        }
+
+        public virtual void CreateMemberAssignementForExistingTarget()
+        {
+            if (PropertiesMapping.Count > 0)
+            {
+                // 用于更改原始表达式的参数。
+                var paramTarget = Expression.Parameter(TargetType, paramClassSource.Name.Replace("s", "t"));
+                ChangParameterExpressionVisitor visitSource = new ChangParameterExpressionVisitor(paramClassSource);
+                ChangParameterExpressionVisitor visitTarget = new ChangParameterExpressionVisitor(paramTarget);
+
+                List<Expression> finalAssign = new List<Expression>();
+
+                foreach (var item in PropertiesMapping)
+                {
+                    var propToAssign = visitTarget.Visit(item.Item2);
+                    var assignExpression = visitSource.Visit(item.Item1);
+                    Type sourceType = TypeSystem.GetElementType(item.Item2.Type);
+                    Type targetType = TypeSystem.GetElementType(item.Item1.Type);
+                    if (string.IsNullOrEmpty(item.Item4))
+                    {
+                        object defaultValue = MapperHelper.GetDefaultValue(item.Item2.Type);
+                        Expression defaultExpression = Expression.Constant(defaultValue, item.Item2.Type);
+                        Expression checkIfNull = Expression.NotEqual(assignExpression, defaultExpression);
+                        if (item.Item3)
+                        {
+                            Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression));
+                            finalAssign.Add(setIf);
+                        }
+                        else
+                        {
+                            if (!IsListOf(propToAssign.Type))
+                            {
+                                finalAssign.Add(Expression.Assign(propToAssign, assignExpression));
+                            }
+                            else
+                            {
+                                if (sourceType == targetType)
+                                {
+                                    Expression toListExp = Expression.Call(_toListMethod.MakeGenericMethod(sourceType), assignExpression);
+                                    Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression));
+                                    finalAssign.Add(setIf);
+                                }
+                            }
+                        }
+                    }
+                    else // 来自其他映射器。
+                    {
+                        var mapper = GetMapper(sourceType, targetType, false, item.Item4);
+                        if (mapper != null)
+                        {
+                            mapper.Initialize(_constructorFunc);
+
+                            Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(item.Item2.Type), item.Item2.Type);
+                            if (!IsListOf(propToAssign.Type))
+                            {
+                                ChangParameterExpressionVisitor changeVisitor = new ChangParameterExpressionVisitor(propToAssign, assignExpression);
+
+                                Expression modifiedExpression = changeVisitor.Visit(mapper.expressionForExisting.Body);
+                                Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression);
+                                Expression setIf = Expression.IfThen(checkIfNull, modifiedExpression);
+                                assignExpression = setIf;
+                            }
+                            else
+                            {
+                                Expression selectExp = Expression.Call(_selectMethod.MakeGenericMethod(sourceType), Expression.Constant(mapper.GetDelegate()));
+                                Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression);
+                                Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression));
+                                assignExpression = setIf;
+                            }
+
+                            finalAssign.Add(assignExpression);
+                        }
+                    }
+                }
+
+                if (finalAssign.Count > 0 && _delegateCallForExisting == null)
+                {
+                    expressionForExisting = Expression.Lambda(Expression.Block(typeof(void), finalAssign), paramClassSource, paramTarget);
+                    // 编译
+                    _delegateCallForExisting = expressionForExisting.Compile();
+                }
+            }
+        }
+
+        internal Expression GetLambdaDest(string propertyName)
+        {
+            var exp = PropertiesMapping.Find(x => GetPropertyInfo(x.Item1).Name == propertyName);
+            if (exp != null)
+            {
+                var final = exp.Item2;
+                if (final.NodeType == ExpressionType.Convert)
+                {
+                    final = (final as UnaryExpression).Operand;
+                }
+
+                return final;
+            }
+
+            return null;
+        }
+
+        public virtual void CreateMappingExpression(Func<Type, object> constructor)
+        {
+            if (!_isInitialized)
+            {
+                // 它是在处理前放置以避免递归循环。
+                _isInitialized = true;
+                _constructorFunc = constructor;
+                CreateCommonMember();
+                var propsToAnalyse = PropertiesMapping.ToList(); // 克隆列表以便于更改。
+                for (int i = 0; i < propsToAnalyse.Count; i++)
+                {
+                    var propToAnalyse = propsToAnalyse[i];
+                    CheckAndConfigureMapping(ref propToAnalyse);
+                    propsToAnalyse[i] = propToAnalyse;
+                }
+
+                PropertiesMapping = propsToAnalyse;
+                // 编译
+                GetDelegate();
+            }
+        }
+
+        internal Type GetRealType(Type typeToFind)
+        {
+            if (UseServiceLocator)
+                return _constructorFunc(typeToFind).GetType();
+            return typeToFind;
+        }
+
+        internal PropertiesNotMapped GetPropertiesNotMapped()
+        {
+            PropertiesNotMapped result = new PropertiesNotMapped();
+            // 克隆属性信息
+            List<PropertyInfo> sourceProperties = SourceType.GetProperties().ToList();
+            List<PropertyInfo> targetProperties = TargetType.GetProperties().ToList();
+
+            PropertiesVisitor visitor = new PropertiesVisitor(TargetType);
+            foreach (var members in memberForNew)
+            {
+                var members1 = members;
+                sourceProperties.RemoveAll((p) => members1.Member.Name == p.Name);
+                targetProperties.RemoveAll((p) => visitor.GetProperties(members.Expression).Contains(p));
+            }
+
+            // 检查被忽略映射的成员
+            sourceProperties.RemoveAll((p) => _propertiesToIgnore.Contains(p));
+            result.sourceProperties = sourceProperties;
+            result.targetProperties = targetProperties;
+
+            return result;
+        }
+
+        public LambdaExpression GetSortedExpression(string propertySource)
+        {
+            Expression result = null;
+            var exp = PropertiesMapping.Find(x => GetPropertyInfo(x.Item2).Name == propertySource);
+            if (exp == null)
+            {
+                throw new PropertyNoExistException(propertySource, TargetType);
+            }
+
+            // 更改参数
+            var visitor = new MapperExpressionVisitor(paramClassSource);
+            result = visitor.Visit(exp.Item1);
+            return Expression.Lambda(result, paramClassSource);
+        }
+
+        private static bool IsListOf(Type typeTarget)
+        {
+            // 特殊情况字符串是char数组。
+            if (typeTarget == typeof(string))
+            {
+                return false;
+            }
+
+            Func<Type, bool> test = t => t.IsAssignableFrom(typeof(IEnumerable));
+            return test(typeTarget) || typeTarget.GetInterfaces().Any(test);
+        }
+
+        private MapperConfigurationBase GetAndCheckMapper(Type typeOfSource, Type typeOfTarget, string name)
+        {
+            var externalMapper = GetMapper(typeOfSource, typeOfTarget, false, name);
+            if (externalMapper != null)
+            {
+                return externalMapper;
+            }
+
+            //如果找不到具有别名的映射器
+            if (!string.IsNullOrEmpty(name))
+            {
+                throw new NoFoundMapperException(name);
+            }
+
+            throw new NotSameTypePropertyException(typeOfSource, typeOfTarget);
+        }
+
+        private void CreatBindingFromSimple(ref Tuple<Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget)
+        {
+            // 没有特殊的操作
+            if (typeSource == typeTarget)
+            {
+                // 创建成员绑定
+                CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3);
+            }
+            else
+            {
+                // 尝试查找mapper
+                MapperConfigurationBase externalMapper = GetAndCheckMapper(typeSource, typeTarget, configExpression.Item4);
+                // 如果此时未初始化映射器
+                externalMapper.CreateMappingExpression(_constructorFunc);
+                // 默认情况下,检查对象的null
+                Expression mapExpression = externalMapper.GetMemberInitExpression();
+                Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(configExpression.Item1.Type), configExpression.Item1.Type);
+                // 修改成员
+                Expression expSource = visitorMapper.Visit(configExpression.Item1, false);
+                ChangParameterExpressionVisitor changeParamaterVisitor = new ChangParameterExpressionVisitor(expSource);
+                mapExpression = changeParamaterVisitor.Visit(mapExpression);
+                // 现在可以创建正确的参数。
+                Expression checkIfNull = Expression.NotEqual(expSource, defaultExpression);
+                // 创建条件
+                var checkExpression = Expression.Condition(checkIfNull, mapExpression, Expression.Constant(MapperHelper.GetDefaultValue(mapExpression.Type), mapExpression.Type), mapExpression.Type);
+                MemberAssignment bindExpression = Expression.Bind(propTarget, checkExpression);
+                // 找到了映射器但没有配置
+                if (string.IsNullOrEmpty(configExpression.Item4))
+                {
+                    configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name);
+                }
+
+                memberForNew.Add(bindExpression);
+            }
+        }
+
+        private void CreateBindingFromList(ref Tuple<Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget)
+        {
+            Type sourceTypeList = TypeSystem.GetElementType(typeSource);
+            Type destTypeList = TypeSystem.GetElementType(typeTarget);
+            if (sourceTypeList == destTypeList)
+            {
+                if (configExpression.Item2.NodeType == ExpressionType.MemberAccess)
+                {
+                    CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3);
+                }
+            }
+            // 使用Enumerable类的select方法来更改类型
+            else
+            {
+                var externalMapper = GetAndCheckMapper(sourceTypeList, destTypeList, configExpression.Item4);
+                externalMapper.CreateMappingExpression(_constructorFunc);
+                MemberAssignment expBind;
+                Expression expSource = configExpression.Item1;
+
+                ChangParameterExpressionVisitor visitor = new ChangParameterExpressionVisitor(paramClassSource);
+                expSource = visitor.Visit(expSource);
+
+                // 为了与EF / LINQ2SQL兼容。
+                LambdaExpression expMappeur = externalMapper.GetGenericLambdaExpression();
+                // 创建对Select方法的调用,在Enumerable的Select中插入一个lambda表达式(参数是一个委托),通常情况下,这是不可能的,但(个人认为)编译器就像这样创建并且LINQ2SQL / EF是可以进行sql查询的
+                Expression select = Expression.Call(_selectMethod.MakeGenericMethod(sourceTypeList, destTypeList), new Expression[]
+                {
+                    expSource,
+                    expMappeur
+                });
+                // 创建对ToList方法的调用
+                Expression toList = Expression.Call(_toListMethod.MakeGenericMethod(destTypeList), select);
+
+                if (configExpression.Item3) // 如果要检查无效(使用EF / LinqTosql,则不需要)。
+                {
+                    // 测试source的属性是否为null。
+                    Expression checkIfNull = Expression.NotEqual(expSource, Expression.Constant(MapperHelper.GetDefaultValue(expSource.Type), expSource.Type));
+                    // 有时候ToList方法不起作用,则使用实现ToList不起作用的类
+                    Expression asExp = Expression.TypeAs(toList, propTarget.PropertyType);
+                    // 创建条件表达式
+                    Expression expCondition = Expression.Condition(checkIfNull, asExp, Expression.Constant(MapperHelper.GetDefaultValue(typeTarget), typeTarget));
+
+                    // 分配给目标属性。
+                    expBind = Expression.Bind(propTarget, expCondition);
+                }
+                else
+                {
+                    // 分配给目标属性。
+                    expBind = Expression.Bind(propTarget, toList);
+                }
+
+                // 查找mapper
+                if (string.IsNullOrEmpty(configExpression.Item4))
+                {
+                    configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name);
+                }
+
+                memberForNew.Add(expBind);
+            }
+        }
+    }
+}

+ 108 - 0
Masuit.Tools/Mapping/Core/MapperConfigurationCollectionContainer.cs

@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Masuit.Tools.Mapping.Core
+{
+    /// <summary>
+    /// 单例存储映射器。
+    /// </summary>
+    /// <remarks>不需要单例,因为适用于所有线程。</remarks>
+    public class MapperConfigurationCollectionContainer : IEnumerable<MapperConfigurationBase>
+    {
+        private readonly HashSet<MapperConfigurationBase> _items;
+        private static MapperConfigurationCollectionContainer currentInstance;
+
+        private MapperConfigurationCollectionContainer()
+        {
+            _items = new HashSet<MapperConfigurationBase>();
+        }
+
+
+        public static MapperConfigurationCollectionContainer Instance => currentInstance ?? (currentInstance = new MapperConfigurationCollectionContainer());
+
+        public int Count => _items.Count;
+
+        internal MapperConfigurationBase this[int index]
+        {
+            get
+            {
+                if (index > _items.Count)
+                    throw new IndexOutOfRangeException();
+                var enumerator = GetEnumerator();
+                int i = 0;
+                while (enumerator.MoveNext())
+                {
+                    if (i == index)
+                    {
+                        return enumerator.Current;
+                    }
+                    i++;
+                }
+
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 查找指定的源。
+        /// </summary>
+        /// <param name="source">源类型</param>
+        /// <param name="target">目标对象</param>
+        /// <param name="name">别名</param>
+        internal MapperConfigurationBase Find(Type source, Type target, string name = null)
+        {
+            foreach (var current in this)
+            {
+                string nameMapper = string.IsNullOrEmpty(name) ? current.paramClassSource.Name : name;
+                if (current.SourceType == source && current.TargetType == target && current.Name == nameMapper)
+                {
+                    return current;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 是否存在谓词的映射。
+        /// </summary>
+        /// <param name="match">条件表达式</param>
+        public bool Exists(Func<MapperConfigurationBase, bool> match)
+        {
+            return this.Any(match);
+        }
+
+        public void RemoveAt(int index)
+        {
+            MapperConfigurationBase itemToDelete = this[index];
+            if (itemToDelete != null)
+            {
+                _items.Remove(itemToDelete);
+            }
+        }
+
+        /// <summary>
+        /// 清除
+        /// </summary>
+        public void Clear()
+        {
+            _items.Clear();
+        }
+
+        public void Add(MapperConfigurationBase value)
+        {
+            _items.Add(value);
+        }
+
+        public IEnumerator<MapperConfigurationBase> GetEnumerator()
+        {
+            return _items.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}

+ 35 - 0
Masuit.Tools/Mapping/Core/PropertiesNotMapped.cs

@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Reflection;
+
+namespace Masuit.Tools.Mapping.Core
+{
+    /// <summary>
+    /// 未映射的属性的处理结果。
+    /// </summary>
+    public class PropertiesNotMapped
+    {
+
+        internal List<PropertyInfo> sourceProperties;
+        internal List<PropertyInfo> targetProperties;
+
+        /// <summary>
+        /// 获取未映射的源属性。
+        /// </summary>
+        public ReadOnlyCollection<PropertyInfo> SourceProperties => new ReadOnlyCollection<PropertyInfo>(sourceProperties);
+
+        /// <summary>
+        /// 获取未映射的目标属性。
+        /// </summary>
+        public ReadOnlyCollection<PropertyInfo> TargetProperties => new ReadOnlyCollection<PropertyInfo>(targetProperties);
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public PropertiesNotMapped()
+        {
+            sourceProperties = new List<PropertyInfo>();
+            targetProperties = new List<PropertyInfo>();
+        }
+    }
+}

+ 59 - 0
Masuit.Tools/Mapping/Core/TypePairMapper.cs

@@ -0,0 +1,59 @@
+using System;
+
+namespace Masuit.Tools.Mapping.Core
+{
+    internal struct TypePairMapper : IEquatable<TypePairMapper>
+    {
+        public TypePairMapper(Type source, Type target, string name = null) : this()
+        {
+            Target = target;
+            Source = source;
+            Name = name;
+        }
+
+        public Type Source { get; private set; }
+        public Type Target { get; private set; }
+
+        public string Name { get; private set; }
+
+        public static TypePairMapper Create(Type source, Type target, string name = null)
+        {
+            return new TypePairMapper(source, target, name);
+        }
+
+        public static TypePairMapper Create<TSource, TTarget>(string name = null)
+        {
+            return new TypePairMapper(typeof(TSource), typeof(TTarget), name);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj))
+            {
+                return false;
+            }
+            return obj is TypePairMapper && Equals((TypePairMapper)obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return ((Source != null ? Source.GetHashCode() : 0) * 397) ^ (Target != null ? Target.GetHashCode() : 0);
+            }
+        }
+        public bool Equals(TypePairMapper other)
+        {
+            bool result;
+            if (!string.IsNullOrEmpty(other.Name))
+            {
+                result = Source == other.Source && Target == other.Target && Name == other.Name;
+            }
+            else
+            {
+                result = Source == other.Source && Target == other.Target;
+            }
+            return result;
+        }
+    }
+}

+ 0 - 105
Masuit.Tools/Mapping/EnumerableCopier.cs

@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-
-namespace Masuit.Tools.Mapping
-{
-    /// <summary>
-    /// 可遍历类型拷贝器
-    /// </summary>
-    internal class EnumerableCopier
-    {
-        private static readonly MethodInfo _copyArrayMethodInfo;
-
-        private static readonly MethodInfo _copyICollectionMethodInfo;
-
-        private static readonly Type _typeICollection = typeof(ICollection<>);
-
-        static EnumerableCopier()
-        {
-            Type type = typeof(EnumerableCopier);
-            _copyArrayMethodInfo = type.GetMethod(nameof(CopyArray));
-            _copyICollectionMethodInfo = type.GetMethod(nameof(CopyICollection));
-        }
-
-        /// <summary>
-        /// 根据IEnumerable的实现类类型选择合适的拷贝方法
-        /// </summary>
-        /// <param name="type">IEnumerable的实现类类型</param>
-        /// <returns>拷贝方法信息</returns>
-        public static MethodInfo GetMethondInfo(Type type)
-        {
-            if (type.IsArray)
-            {
-                return _copyArrayMethodInfo.MakeGenericMethod(type.GetElementType());
-            }
-
-            if (type.GetGenericArguments().Length > 0)
-            {
-                Type elementType = type.GetGenericArguments()[0];
-                if (_typeICollection.MakeGenericType(elementType).IsAssignableFrom(type))
-                {
-                    return _copyICollectionMethodInfo.MakeGenericMethod(type, elementType);
-                }
-            }
-
-            throw new UnsupportedTypeException(type);
-        }
-
-        /// <summary>
-        /// 拷贝List
-        /// </summary>
-        /// <typeparam name="T">源ICollection实现类类型</typeparam>
-        /// <typeparam name="TElement">源ICollection元素类型</typeparam>
-        /// <param name="source">源ICollection对象</param>
-        /// <returns>深拷贝完成的ICollection对象</returns>
-        public static T CopyICollection<T, TElement>(T source) where T : ICollection<TElement> where TElement : class
-        {
-            T result = (T)MapperTools.CreateNewInstance(source.GetType());
-
-            if (MapperTools.IsRefTypeExceptString(typeof(TElement)))
-            {
-                foreach (TElement item in source)
-                {
-                    result.Add(ExpressionGenericMapper<TElement, TElement>.Copy(item));
-                }
-            }
-            else
-            {
-                foreach (TElement item in source)
-                {
-                    result.Add(item);
-                }
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// 拷贝数组
-        /// </summary>
-        /// <typeparam name="TElement">源数组元素类型</typeparam>
-        /// <param name="source">源List</param>
-        /// <returns>深拷贝完成的数组</returns>
-        public static TElement[] CopyArray<TElement>(TElement[] source) where TElement : class
-        {
-            TElement[] result = new TElement[source.Length];
-            if (MapperTools.IsRefTypeExceptString(typeof(TElement)))
-            {
-                for (int i = 0; i < source.Length; i++)
-                {
-                    result[i] = ExpressionGenericMapper<TElement, TElement>.Copy(source[i]);
-                }
-            }
-            else
-            {
-                for (int i = 0; i < source.Length; i++)
-                {
-                    result[i] = source[i];
-                }
-            }
-
-            return result;
-        }
-    }
-}

+ 56 - 0
Masuit.Tools/Mapping/Exceptions/MapperExceptionBase.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// mapper异常基类
+    /// </summary>
+    [Serializable]
+    public class MapperExceptionBase : Exception
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        public MapperExceptionBase(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+
+        /// <summary>
+        /// 无参构造函数
+        /// </summary>
+        public MapperExceptionBase()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected MapperExceptionBase(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public MapperExceptionBase(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+
+        /// <summary>
+        /// 验证参数
+        /// </summary>
+        /// <param name="message">消息</param>
+        /// <param name="conditions">条件</param>
+        /// <returns>异常信息</returns>
+        protected static string ValideParameter(string message, params bool[] conditions)
+        {
+            return message;
+        }
+    }
+}

+ 55 - 0
Masuit.Tools/Mapping/Exceptions/MapperExistException.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 映射已存在时的异常
+    /// </summary>
+    [Serializable]
+    public class MapperExistException : MapperExceptionBase
+
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="source">源类型</param>
+        /// <param name="dest">目标类型</param>
+        public MapperExistException(Type source, Type dest) : base(ValideParameter($"对于源“{source.FullName}”的类型和目标类型“{dest.FullName}”的映射关系已经存在", source != null, dest != null))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public MapperExistException()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        public MapperExistException(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected MapperExistException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public MapperExistException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+    }
+}

+ 54 - 0
Masuit.Tools/Mapping/Exceptions/MapperNotInitializedException.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 映射未初始化时的异常
+    /// </summary>
+    [Serializable]
+    public class MapperNotInitializedException : MapperExceptionBase
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="typeSource">源类型</param>
+        /// <param name="typeDest">目标类型</param>
+        public MapperNotInitializedException(Type typeSource, Type typeDest) : base(ValideParameter($"源类型“{typeSource.FullName}”和目标类型“{typeDest.FullName}”的映射关系未被初始化,需要在此之前调用ExpressionMapper.Initialize()", typeSource != null, typeDest != null))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public MapperNotInitializedException()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        public MapperNotInitializedException(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected MapperNotInitializedException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public MapperNotInitializedException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+    }
+}

+ 46 - 0
Masuit.Tools/Mapping/Exceptions/NoActionAfterMappingException.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 无法执行任何操作时的异常
+    /// </summary>
+    /// <seealso cref="MapperExceptionBase" />
+    [Serializable]
+    public class NoActionAfterMappingException : MapperExceptionBase
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public NoActionAfterMappingException() : base("无法执行操作,因为操作未定义")
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected NoActionAfterMappingException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        public NoActionAfterMappingException(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public NoActionAfterMappingException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+    }
+}

+ 54 - 0
Masuit.Tools/Mapping/Exceptions/NoFoundMapperException.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 未找到映射关系时出现异常
+    /// </summary>
+    [Serializable]
+    public class NoFoundMapperException : MapperExceptionBase
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="source">源类型</param>
+        /// <param name="dest">目标类型</param>
+        public NoFoundMapperException(Type source, Type dest) : base(ValideParameter($"未配置类型“{source.Name}”和“{dest.Name}”的映射", source != null, dest != null))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="name">别名</param>
+        public NoFoundMapperException(string name) : base(ValideParameter($"找不到名称为{name}的映射", !string.IsNullOrEmpty(name)))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public NoFoundMapperException()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected NoFoundMapperException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public NoFoundMapperException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+    }
+}

+ 53 - 0
Masuit.Tools/Mapping/Exceptions/NotSameTypePropertyException.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 当属性不是同一类型或找不到映射器时出现异常
+    /// </summary>
+    [Serializable]
+    public class NotSameTypePropertyException : MapperExceptionBase
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="typeSource">源类型</param>
+        /// <param name="typeDest">目标类型</param>
+        public NotSameTypePropertyException(Type typeSource, Type typeDest) : base(ValideParameter($"源类型{typeSource.Name}目标和类型{typeDest.Name}的属性不是同一类型或找不到映射关系", typeSource != null, typeDest != null))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public NotSameTypePropertyException()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected NotSameTypePropertyException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public NotSameTypePropertyException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public NotSameTypePropertyException(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+    }
+}

+ 54 - 0
Masuit.Tools/Mapping/Exceptions/PropertyNoExistException.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 找不到属性时出现异常
+    /// </summary>
+    [Serializable]
+    public class PropertyNoExistException : MapperExceptionBase
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="propertyName">属性名</param>
+        /// <param name="typeObject">对象类型</param>
+        public PropertyNoExistException(string propertyName, Type typeObject) : base(ValideParameter($"类型“{typeObject}”不存在属性“{propertyName}”", !String.IsNullOrEmpty(propertyName), typeObject != null))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public PropertyNoExistException()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        public PropertyNoExistException(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected PropertyNoExistException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public PropertyNoExistException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+    }
+}

+ 59 - 0
Masuit.Tools/Mapping/Exceptions/ReadOnlyPropertyException.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Reflection;
+using System.Runtime.Serialization;
+
+namespace Masuit.Tools.Mapping.Exceptions
+{
+    /// <summary>
+    /// 只读属性的异常
+    /// </summary>
+    [Serializable]
+    public class ReadOnlyPropertyException : MapperExceptionBase
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="property">属性</param>
+        public ReadOnlyPropertyException(PropertyInfo property) : base(ValidateParameter(property))
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public ReadOnlyPropertyException()
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="serializer">序列化信息</param>
+        /// <param name="context">上下文</param>
+        protected ReadOnlyPropertyException(SerializationInfo serializer, StreamingContext context) : base(serializer, context)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        /// <param name="innerException">内部异常</param>
+        public ReadOnlyPropertyException(string exceptionMessage, Exception innerException) : base(exceptionMessage, innerException)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="exceptionMessage">异常信息</param>
+        public ReadOnlyPropertyException(string exceptionMessage) : base(exceptionMessage)
+        {
+        }
+
+        private static string ValidateParameter(PropertyInfo property)
+        {
+            return $"目标对象的属性 '{property.Name}' 是只读的";
+        }
+    }
+}

+ 10 - 0
Masuit.Tools/Mapping/ExpressionCpoier.cs

@@ -0,0 +1,10 @@
+namespace Masuit.Tools.Mapping
+{
+    public static class ExpressionCpoier
+    {
+        public static T Copy<T>(this T source)
+        {
+            return Copier<T>.Copy(source);
+        }
+    }
+}

+ 0 - 466
Masuit.Tools/Mapping/ExpressionGenericMapper.cs

@@ -1,466 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations.Schema;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
-
-namespace Masuit.Tools.Mapping
-{
-    /// <summary>
-    /// 表达式树实体映射器
-    /// </summary>
-    /// <typeparam name="TSource"></typeparam>
-    /// <typeparam name="TDest"></typeparam>
-    public static class ExpressionGenericMapper<TSource, TDest> where TSource : class where TDest : class
-    {
-        // 缓存委托
-        private static Func<TSource, TDest> MapFunc;
-        private static Action<TSource, TDest> MapAction;
-        private static Func<TSource, TDest> _copyFunc;
-        private static Action<TSource, TDest> _copyAction;
-
-        /// <summary>
-        /// 对象映射
-        /// </summary>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static TDest Map(TSource source)
-        {
-            if (MapFunc == null)
-            {
-                MapFunc = GetMapFunc();
-            }
-
-            return MapFunc(source);
-        }
-
-        /// <summary>
-        /// 集合映射
-        /// </summary>
-        /// <param name="sources"></param>
-        /// <returns></returns>
-        public static List<TDest> MapList(IEnumerable<TSource> sources)
-        {
-            if (MapFunc == null)
-            {
-                MapFunc = GetMapFunc();
-            }
-
-            return sources.Select(MapFunc).ToList();
-        }
-
-        /// <summary>
-        /// 映射到已经实例化的对象
-        /// </summary>
-        /// <param name="source"></param>
-        /// <param name="target"></param>
-        public static void Map(TSource source, TDest target)
-        {
-            if (MapAction == null)
-            {
-                MapAction = GetMapAction();
-            }
-
-            MapAction(source, target);
-        }
-
-        private static Func<TSource, TDest> GetMapFunc()
-        {
-            var sourceType = typeof(TSource);
-            var targetType = typeof(TDest);
-
-            if (MapperTools.IsEnumerable(sourceType) || MapperTools.IsEnumerable(targetType))
-            {
-                throw new NotSupportedException("数组类型暂不支持对象映射,请使用List类型");
-            }
-
-            //Func委托传入变量
-            var parameter = Expression.Parameter(sourceType, "p");
-
-            var memberBindings = new List<MemberBinding>();
-            var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite);
-            foreach (var targetItem in targetTypes)
-            {
-                var sourceItem = sourceType.GetProperty(targetItem.Name);
-
-                //判断对象的读写权限
-                if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
-                {
-                    continue;
-                }
-
-                //标注NotMapped特性的属性忽略转换
-                if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
-                {
-                    continue;
-                }
-
-                var sourceProperty = Expression.Property(parameter, sourceItem);
-
-                //当非值类型且类型不相同时
-                if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType)
-                {
-                    //判断都是(非泛型、非数组)class
-                    if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass && !sourceItem.PropertyType.IsArray && !targetItem.PropertyType.IsArray && !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType)
-                    {
-                        var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        memberBindings.Add(Expression.Bind(targetItem, expression));
-                    }
-
-                    //集合数组类型的转换
-                    if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType))
-                    {
-                        var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        memberBindings.Add(Expression.Bind(targetItem, expression));
-                    }
-
-                    continue;
-                }
-
-                //可空类型转换到非可空类型,当可空类型值为null时,用默认值赋给目标属性;不为null就直接转换
-                if (MapperTools.IsNullableType(sourceItem.PropertyType) && !MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var hasValueExpression = Expression.Equal(Expression.Property(sourceProperty, "HasValue"), Expression.Constant(true));
-                    var conditionItem = Expression.Condition(hasValueExpression, Expression.Convert(sourceProperty, targetItem.PropertyType), Expression.Default(targetItem.PropertyType));
-                    memberBindings.Add(Expression.Bind(targetItem, conditionItem));
-                    continue;
-                }
-
-                //非可空类型转换到可空类型,直接转换
-                if (!MapperTools.IsNullableType(sourceItem.PropertyType) && MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var memberExpression = Expression.Convert(sourceProperty, targetItem.PropertyType);
-                    memberBindings.Add(Expression.Bind(targetItem, memberExpression));
-                    continue;
-                }
-
-                if (targetItem.PropertyType != sourceItem.PropertyType)
-                {
-                    continue;
-                }
-
-                memberBindings.Add(Expression.Bind(targetItem, sourceProperty));
-            }
-
-            //创建一个if条件表达式
-            var test = Expression.NotEqual(parameter, Expression.Constant(null, sourceType)); // p==null;
-            var ifTrue = Expression.MemberInit(Expression.New(targetType), memberBindings);
-            var condition = Expression.Condition(test, ifTrue, Expression.Constant(null, targetType));
-
-            var lambda = Expression.Lambda<Func<TSource, TDest>>(condition, parameter);
-            return lambda.Compile();
-        }
-
-        /// <summary>
-        /// 类型是clas时赋值
-        /// </summary>
-        /// <param name="sourceProperty"></param>
-        /// <param name="sourceType"></param>
-        /// <param name="targetType"></param>
-        /// <returns></returns>
-        private static Expression GetClassExpression(Expression sourceProperty, Type sourceType, Type targetType)
-        {
-            //条件p.Item!=null
-            var testItem = Expression.NotEqual(sourceProperty, Expression.Constant(null, sourceType));
-
-            //构造回调
-            var mapperType = typeof(ExpressionGenericMapper<,>).MakeGenericType(sourceType, targetType);
-            var iftrue = Expression.Call(mapperType.GetMethod(nameof(Map), new[]
-            {
-                sourceType
-            }), sourceProperty);
-            var conditionItem = Expression.Condition(testItem, iftrue, Expression.Constant(null, targetType));
-            return conditionItem;
-        }
-
-        /// <summary>
-        /// 类型为集合时赋值
-        /// </summary>
-        /// <param name="sourceProperty"></param>
-        /// <param name="sourceType"></param>
-        /// <param name="targetType"></param>
-        /// <returns></returns>
-        private static Expression GetListExpression(Expression sourceProperty, Type sourceType, Type targetType)
-        {
-            //条件p.Item!=null
-            var testItem = Expression.NotEqual(sourceProperty, Expression.Constant(null, sourceType));
-
-            //构造回调
-            var sourceArg = sourceType.IsArray ? sourceType.GetElementType() : sourceType.GetGenericArguments()[0];
-            var targetArg = targetType.IsArray ? targetType.GetElementType() : targetType.GetGenericArguments()[0];
-            var mapperType = typeof(ExpressionGenericMapper<,>).MakeGenericType(sourceArg, targetArg);
-            var mapperExecMap = Expression.Call(mapperType.GetMethod(nameof(MapList), new[]
-            {
-                sourceType
-            }), sourceProperty);
-            Expression iftrue;
-            if (targetType == mapperExecMap.Type)
-            {
-                iftrue = mapperExecMap;
-            }
-            else if (targetType.IsArray) //数组类型调用ToArray()方法
-            {
-                iftrue = Expression.Call(typeof(Enumerable), nameof(Enumerable.ToArray), new[]
-                {
-                    mapperExecMap.Type.GenericTypeArguments[0]
-                }, mapperExecMap);
-            }
-            else if (typeof(IDictionary).IsAssignableFrom(targetType))
-            {
-                iftrue = Expression.Constant(null, targetType); //字典类型不转换
-            }
-            else
-            {
-                iftrue = Expression.Convert(mapperExecMap, targetType);
-            }
-
-            var conditionItem = Expression.Condition(testItem, iftrue, Expression.Constant(null, targetType));
-            return conditionItem;
-        }
-
-        private static Action<TSource, TDest> GetMapAction()
-        {
-            var sourceType = typeof(TSource);
-            var targetType = typeof(TDest);
-
-            if (MapperTools.IsEnumerable(sourceType) || MapperTools.IsEnumerable(targetType))
-            {
-                throw new NotSupportedException("数组类型暂不支持对象映射,请使用List类型");
-            }
-
-            //Func委托传入变量
-            var sourceParameter = Expression.Parameter(sourceType, "p");
-            var targetParameter = Expression.Parameter(targetType, "t");
-
-            //创建一个表达式集合
-            var expressions = new List<Expression>();
-            var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite);
-            foreach (var targetItem in targetTypes)
-            {
-                var sourceItem = sourceType.GetProperty(targetItem.Name);
-
-                //判断对象的读写权限
-                if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
-                {
-                    continue;
-                }
-
-                //标注NotMapped特性的属性忽略转换
-                if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
-                {
-                    continue;
-                }
-
-                var sourceProperty = Expression.Property(sourceParameter, sourceItem);
-                var targetProperty = Expression.Property(targetParameter, targetItem);
-
-                //当非值类型且类型不相同时
-                if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType)
-                {
-                    //判断都是(非泛型、非数组)class
-                    if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass && !sourceItem.PropertyType.IsArray && !targetItem.PropertyType.IsArray && !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType)
-                    {
-                        var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        expressions.Add(Expression.Assign(targetProperty, expression));
-                    }
-
-                    //集合数组类型的转换
-                    if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType))
-                    {
-                        var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
-                        expressions.Add(Expression.Assign(targetProperty, expression));
-                    }
-
-                    continue;
-                }
-
-                //可空类型转换到非可空类型,当可空类型值为null时,用默认值赋给目标属性;不为null就直接转换
-                if (MapperTools.IsNullableType(sourceItem.PropertyType) && !MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var hasValueExpression = Expression.Equal(Expression.Property(sourceProperty, "HasValue"), Expression.Constant(true));
-                    var conditionItem = Expression.Condition(hasValueExpression, Expression.Convert(sourceProperty, targetItem.PropertyType), Expression.Default(targetItem.PropertyType));
-                    expressions.Add(Expression.Assign(targetProperty, conditionItem));
-                    continue;
-                }
-
-                //非可空类型转换到可空类型,直接转换
-                if (!MapperTools.IsNullableType(sourceItem.PropertyType) && MapperTools.IsNullableType(targetItem.PropertyType))
-                {
-                    var memberExpression = Expression.Convert(sourceProperty, targetItem.PropertyType);
-                    expressions.Add(Expression.Assign(targetProperty, memberExpression));
-                    continue;
-                }
-
-                if (targetItem.PropertyType != sourceItem.PropertyType)
-                {
-                    continue;
-                }
-
-                expressions.Add(Expression.Assign(targetProperty, sourceProperty));
-            }
-
-            //当Target!=null判断source是否为空
-            var testSource = Expression.NotEqual(sourceParameter, Expression.Constant(null, sourceType));
-            var ifTrueSource = Expression.Block(expressions);
-            var conditionSource = Expression.IfThen(testSource, ifTrueSource);
-
-            //判断target是否为空
-            var tesTDest = Expression.NotEqual(targetParameter, Expression.Constant(null, targetType));
-            var conditionTarget = Expression.IfThen(tesTDest, conditionSource);
-            var lambda = Expression.Lambda<Action<TSource, TDest>>(conditionTarget, sourceParameter, targetParameter);
-            return lambda.Compile();
-        }
-
-        /// <summary>
-        /// 新建目标类型实例,并将源对象的属性值拷贝至目标对象的对应属性
-        /// </summary>
-        /// <param name="source">源对象实例</param>
-        /// <returns>深拷贝了源对象属性的目标对象实例</returns>
-        public static TDest Copy(TSource source)
-        {
-            if (source == null) return default(TDest);
-
-            // 因为对于泛型类型而言,每次传入不同的泛型参数都会调用静态构造函数,所以可以通过这种方式进行缓存
-            if (_copyFunc != null)
-            {
-                // 如果之前缓存过,则直接调用缓存的委托
-                return _copyFunc(source);
-            }
-
-            Type sourceType = typeof(TSource);
-            Type targetType = typeof(TDest);
-
-            var paramExpr = Expression.Parameter(sourceType, nameof(source));
-
-            Expression bodyExpr;
-
-            // 如果对象可以遍历(目前只支持数组和ICollection<T>实现类)
-            if (sourceType == targetType && MapperTools.IsIEnumerableExceptString(sourceType))
-            {
-                bodyExpr = Expression.Call(null, EnumerableCopier.GetMethondInfo(sourceType), paramExpr);
-            }
-            else
-            {
-                var memberBindings = new List<MemberBinding>();
-                // 遍历目标对象的所有属性信息
-                foreach (var targetPropInfo in targetType.GetProperties())
-                {
-                    // 从源对象获取同名的属性信息
-                    var sourcePropInfo = sourceType.GetProperty(targetPropInfo.Name);
-
-                    Type sourcePropType = sourcePropInfo?.PropertyType;
-                    Type targetPropType = targetPropInfo.PropertyType;
-
-                    // 只在满足以下三个条件的情况下进行拷贝
-                    // 1.源属性类型和目标属性类型一致
-                    // 2.源属性可读
-                    // 3.目标属性可写
-                    if (sourcePropType == targetPropType && sourcePropInfo.CanRead && targetPropInfo.CanWrite)
-                    {
-                        // 获取属性值的表达式
-                        Expression expression = Expression.Property(paramExpr, sourcePropInfo);
-
-                        // 如果目标属性是值类型或者字符串,则直接做赋值处理
-                        // 暂不考虑目标值类型有非字符串的引用类型这种特殊情况
-                        // 非字符串引用类型做递归处理
-                        if (MapperTools.IsRefTypeExceptString(targetPropType))
-                        {
-                            // 进行递归
-                            if (MapperTools.IsRefTypeExceptString(targetPropType))
-                            {
-                                expression = Expression.Call(null, GetCopyMethodInfo(sourcePropType, targetPropType), expression);
-                            }
-                        }
-
-                        memberBindings.Add(Expression.Bind(targetPropInfo, expression));
-                    }
-                }
-
-                bodyExpr = Expression.MemberInit(Expression.New(targetType), memberBindings);
-            }
-
-            var lambdaExpr = Expression.Lambda<Func<TSource, TDest>>(bodyExpr, paramExpr);
-
-            _copyFunc = lambdaExpr.Compile();
-            return _copyFunc(source);
-        }
-
-        /// <summary>
-        /// 新建目标类型实例,并将源对象的属性值拷贝至目标对象的对应属性
-        /// </summary>
-        /// <param name="source">源对象实例</param>
-        /// <param name="target">目标对象实例</param>
-        public static void Copy(TSource source, TDest target)
-        {
-            if (source == null) return;
-
-            // 因为对于泛型类型而言,每次传入不同的泛型参数都会调用静态构造函数,所以可以通过这种方式进行缓存
-            // 如果之前缓存过,则直接调用缓存的委托
-            if (_copyAction != null)
-            {
-                _copyAction(source, target);
-                return;
-            }
-
-            Type sourceType = typeof(TSource);
-            Type targetType = typeof(TDest);
-
-            // 如果双方都可以被遍历
-            if (MapperTools.IsIEnumerableExceptString(sourceType) && MapperTools.IsIEnumerableExceptString(targetType))
-            {
-                // TODO
-                // 向已存在的数组或者ICollection<T>拷贝的功能暂不支持
-            }
-            else
-            {
-                var paramSourceExpr = Expression.Parameter(sourceType, nameof(source));
-                var paramTargetExpr = Expression.Parameter(targetType, nameof(target));
-
-                var binaryExpressions = new List<Expression>();
-                // 遍历目标对象的所有属性信息
-                foreach (var targetPropInfo in targetType.GetProperties())
-                {
-                    // 从源对象获取同名的属性信息
-                    var sourcePropInfo = sourceType.GetProperty(targetPropInfo.Name);
-
-                    Type sourcePropType = sourcePropInfo?.PropertyType;
-                    Type targetPropType = targetPropInfo.PropertyType;
-
-                    // 只在满足以下三个条件的情况下进行拷贝
-                    // 1.源属性类型和目标属性类型一致
-                    // 2.源属性可读
-                    // 3.目标属性可写
-                    if (sourcePropType == targetPropType && sourcePropInfo.CanRead && targetPropInfo.CanWrite)
-                    {
-                        // 获取属性值的表达式
-                        Expression expression = Expression.Property(paramSourceExpr, sourcePropInfo);
-                        Expression targetPropExpr = Expression.Property(paramTargetExpr, targetPropInfo);
-
-                        // 如果目标属性是值类型或者字符串,则直接做赋值处理
-                        // 暂不考虑目标值类型有非字符串的引用类型这种特殊情况
-                        if (MapperTools.IsRefTypeExceptString(targetPropType))
-                        {
-                            expression = Expression.Call(null, GetCopyMethodInfo(sourcePropType, targetPropType), expression);
-                        }
-
-                        binaryExpressions.Add(Expression.Assign(targetPropExpr, expression));
-                    }
-                }
-
-                Expression bodyExpr = Expression.Block(binaryExpressions);
-
-                var lambdaExpr = Expression.Lambda<Action<TSource, TDest>>(bodyExpr, paramSourceExpr, paramTargetExpr);
-
-                _copyAction = lambdaExpr.Compile();
-                _copyAction(source, target);
-            }
-        }
-
-        private static MethodInfo GetCopyMethodInfo(Type source, Type target) => typeof(ExpressionGenericMapper<,>).MakeGenericType(source, target).GetMethod(nameof(Copy), new[]
-        {
-            source
-        });
-    }
-}

+ 176 - 0
Masuit.Tools/Mapping/ExpressionMapper.cs

@@ -0,0 +1,176 @@
+using Masuit.Tools.Mapping.Core;
+using Masuit.Tools.Mapping.Exceptions;
+using System;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping
+{
+    /// <summary>
+    /// mapper的基类
+    /// </summary>
+    public static class ExpressionMapper
+    {
+        private static Func<Type, object> _constructorFunc;
+        private static bool _initialized;
+
+        /// <summary>
+        /// 映射指定的源。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="source">源对象</param>
+        /// <param name="name">别名</param>
+        /// <returns>
+        /// 目标对象的新实例
+        /// </returns>
+        public static TTarget Map<TSource, TTarget>(this TSource source, string name = null) where TSource : class where TTarget : class
+        {
+            if (source == null)
+            {
+                return null;
+            }
+
+            if (!_initialized)
+            {
+                Initialize();
+            }
+            TTarget result = null;
+            MapperConfiguration<TSource, TTarget> mapper = GetMapper<TSource, TTarget>(name);
+            Func<TSource, TTarget> query = mapper.GetFuncDelegate();
+            if (query != null)
+            {
+                result = query(source);
+                // 映射后执行的操作
+                mapper.ExecuteAfterActions(source, result);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 将指定的源映射到目标。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="source">源对象</param>
+        /// <param name="target">目标对象</param>
+        /// <param name="name">别名</param>
+        public static void Map<TSource, TTarget>(this TSource source, TTarget target, string name = null) where TSource : class where TTarget : class
+        {
+            if (!_initialized)
+            {
+                Initialize();
+            }
+            TTarget result = null;
+            MapperConfiguration<TSource, TTarget> mapper = GetMapper<TSource, TTarget>(name);
+            Action<TSource, TTarget> query = mapper.GetDelegateForExistingTarget() as Action<TSource, TTarget>;
+            if (query != null)
+            {
+                query(source, target);
+                // 映射后执行的操作
+                mapper.ExecuteAfterActions(source, result);
+            }
+        }
+
+        /// <summary>
+        /// 获取查询表达式树
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <returns></returns>
+        public static Expression<Func<TSource, TTarget>> GetQueryExpression<TSource, TTarget>() where TSource : class where TTarget : class
+        {
+            return GetMapper<TSource, TTarget>().GetLambdaExpression();
+        }
+
+        /// <summary>
+        /// 创建mapper对象
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <returns></returns>
+        public static MapperConfiguration<TSource, TTarget> CreateMap<TSource, TTarget>(string name = null) where TSource : class where TTarget : class
+        {
+            MapperConfigurationBase map = MapperConfigurationCollectionContainer.Instance.Find(typeof(TSource), typeof(TTarget), name);
+            if (map == null)
+            {
+                string finalName = string.IsNullOrEmpty(name) ? "s" + MapperConfigurationCollectionContainer.Instance.Count.ToString() : name;
+                map = new MapperConfiguration<TSource, TTarget>(finalName);
+                MapperConfigurationCollectionContainer.Instance.Add(map);
+            }
+            return map as MapperConfiguration<TSource, TTarget>;
+        }
+
+        /// <summary>
+        /// 表示使用的依赖注入服务
+        /// </summary>
+        /// <param name="constructor">构造函数委托</param>
+        public static void ConstructServicesUsing(Func<Type, object> constructor)
+        {
+            _constructorFunc = constructor;
+        }
+
+        /// <summary>
+        /// 重置mapper
+        /// </summary>
+        public static void Reset()
+        {
+            MapperConfigurationCollectionContainer.Instance.Clear();
+        }
+
+        /// <summary>
+        /// 获取mapper实例
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TDest">目标类型</typeparam>
+        /// <param name="name">别名</param>
+        /// <returns></returns>
+        public static MapperConfiguration<TSource, TDest> GetMapper<TSource, TDest>(string name = null) where TSource : class where TDest : class
+        {
+            return GetMapper(typeof(TSource), typeof(TDest), name) as MapperConfiguration<TSource, TDest>;
+        }
+
+        /// <summary>
+        /// 初始化mapper
+        /// </summary>
+        public static void Initialize()
+        {
+            MapperConfigurationCollectionContainer configRegister = MapperConfigurationCollectionContainer.Instance;
+            foreach (var t in configRegister)
+            {
+                t.Initialize(_constructorFunc);
+            }
+            _initialized = true;
+        }
+
+        /// <summary>
+        /// 获取mapper的委托
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TDest">目标类型</typeparam>
+        /// <returns></returns>
+        public static Func<TSource, TDest> GetQuery<TSource, TDest>() where TSource : class where TDest : class
+        {
+            return GetMapper<TSource, TDest>().GetFuncDelegate();
+        }
+
+        /// <summary>
+        /// 获取未映射的属性
+        /// </summary>
+        public static PropertiesNotMapped GetPropertiesNotMapped<TSource, TDest>(string name = null) where TSource : class where TDest : class
+        {
+            var mapper = GetMapper<TSource, TDest>(name);
+            return mapper.GetPropertiesNotMapped();
+        }
+
+        internal static MapperConfigurationBase GetMapper(Type tSource, Type tDest, string name = null)
+        {
+            MapperConfigurationBase mapConfig = MapperConfigurationCollectionContainer.Instance.Find(tSource, tDest, name);
+            if (mapConfig == null)
+            {
+                throw new NoFoundMapperException(tSource, tDest);
+            }
+
+            return mapConfig;
+        }
+    }
+}

+ 77 - 0
Masuit.Tools/Mapping/Extensions/ExpressionExtentions.cs

@@ -0,0 +1,77 @@
+using Masuit.Tools.Mapping.Visitor;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping.Extensions
+{
+    /// <summary>
+    ///表达式树扩展
+    /// </summary>
+    public static class ExpressionExtentions
+    {
+        /// <summary>
+        /// 转换
+        /// </summary>
+        /// <typeparam name="TFrom">源类型</typeparam>
+        /// <param name="from">来源</param>
+        /// <param name="toType">目标类型</param>
+        /// <returns></returns>
+        public static Expression ConvertTo<TFrom>(this Expression<Func<TFrom, object>> from, Type toType)
+        {
+            return ConvertImpl(from, toType);
+        }
+
+        /// <summary>
+        /// 转换
+        /// </summary>
+        /// <typeparam name="TFrom">源类型</typeparam>
+        /// <param name="from">来源</param>
+        /// <param name="toType">目标类型</param>
+        /// <returns></returns>
+        public static Expression ConvertTo<TFrom>(this Expression<Func<TFrom, bool>> from, Type toType)
+        {
+            return ConvertImpl(from, toType);
+        }
+
+        /// <summary>
+        /// 转换Lambda表达式树
+        /// </summary>
+        /// <typeparam name="TFrom">源类型</typeparam>
+        /// <typeparam name="TTo">目标类型</typeparam>
+        /// <param name="from">来源</param>
+        /// <returns></returns>
+        public static Expression ConvertTo<TFrom, TTo>(this Expression<Func<TFrom, object>> from)
+        {
+            return ConvertImpl(from, typeof(TTo));
+        }
+
+        /// <summary>
+        /// 转换表达式树
+        /// </summary>
+        /// <typeparam name="TFrom">源类型的表达式树</typeparam>
+        /// <typeparam name="TTo">目标类型的表达式树</typeparam>
+        /// <param name="from">源类型的表达式树</param>
+        /// <returns>表达式转换或如果没有找到映射原始表达式。</returns>
+        public static Expression<Func<TTo, bool>> ConvertTo<TFrom, TTo>(this Expression<Func<TFrom, bool>> from)
+        {
+            return (Expression<Func<TTo, bool>>)ConvertImpl(from, typeof(TTo));
+        }
+
+        private static Expression ConvertImpl<TFrom>(Expression<TFrom> from, Type toType) where TFrom : class
+        {
+            //  重新映射不同类型的所有参数
+            Dictionary<Expression, Expression> parameterMap = new Dictionary<Expression, Expression>();
+            ParameterExpression[] newParams = new ParameterExpression[from.Parameters.Count];
+            for (int i = 0; i < newParams.Length; i++)
+            {
+                newParams[i] = Expression.Parameter(toType, from.Parameters[i].Name);
+                parameterMap[from.Parameters[i]] = newParams[i];
+            }
+
+            // 重新构建表达式树
+            var body = new ConverterExpressionVisitor(parameterMap, toType).Visit(from.Body);
+            return Expression.Lambda(body, newParams);
+        }
+    }
+}

+ 124 - 0
Masuit.Tools/Mapping/Extensions/QueryableExtentions.cs

@@ -0,0 +1,124 @@
+using Masuit.Tools.Mapping.Core;
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping.Extensions
+{
+    /// <summary>
+    /// IQueryable的扩展
+    /// </summary>
+    public static class QueryableExtentions
+    {
+        /// <summary>
+        /// 根据键按升序对序列的元素进行排序。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        /// <param name="sortedPropertyDestName">目标属性的名称</param>
+        /// <returns></returns>
+        public static IOrderedQueryable<TSource> OrderBy<TSource, TTarget>(this IQueryable<TSource> query, string sortedPropertyDestName) where TSource : class where TTarget : class
+        {
+            // 没有使用MethodBase.GetCurrentMethod().Name,因为效率不高
+            return CreateSortedMethodCall<TSource, TTarget, IOrderedQueryable<TSource>>(query, "OrderBy", sortedPropertyDestName);
+        }
+
+        /// <summary>
+        /// 根据键按降序对序列的元素进行排序。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        /// <param name="sortedPropertyDestName">目标属性的名称</param>
+        /// <returns></returns>
+        public static IOrderedQueryable<TSource> OrderByDescending<TSource, TTarget>(this IQueryable<TSource> query, string sortedPropertyDestName) where TSource : class where TTarget : class
+        {
+            return CreateSortedMethodCall<TSource, TTarget, IOrderedQueryable<TSource>>(query, "OrderByDescending", sortedPropertyDestName);
+        }
+
+        /// <summary>
+        ///  根据键按升序对序列的元素进行排序。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        /// <param name="sortedPropertyDestName">目标属性的名称</param>
+        public static IOrderedQueryable<TSource> ThenBy<TSource, TTarget>(this IQueryable<TSource> query, string sortedPropertyDestName) where TSource : class where TTarget : class
+        {
+            return CreateSortedMethodCall<TSource, TTarget, IOrderedQueryable<TSource>>(query, "ThenBy", sortedPropertyDestName);
+        }
+
+        /// <summary>
+        /// 根据键按降序对序列的元素进行排序。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        /// <param name="sortedPropertyDestName">目标属性的名称</param>
+        public static IOrderedQueryable<TSource> ThenByDescending<TSource, TTarget>(this IQueryable<TSource> query, string sortedPropertyDestName) where TSource : class where TTarget : class
+        {
+            return CreateSortedMethodCall<TSource, TTarget, IOrderedQueryable<TSource>>(query, "ThenByDescending", sortedPropertyDestName);
+        }
+
+        /// <summary>
+        /// 通过合并目标对象将序列的每个元素投影到新表单中。
+        /// </summary>
+        /// <typeparam name="TSource">源类型.</typeparam>
+        /// <typeparam name="TTarget">目标类型.</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        public static IQueryable<TTarget> Select<TSource, TTarget>(this IQueryable<TSource> query) where TSource : class where TTarget : class
+        {
+            return GetSelect<TSource, TTarget>(query, null);
+        }
+
+        /// <summary>
+        /// 通过合并目标对象将序列的每个元素投影到新表单中。
+        /// </summary>
+        /// <typeparam name="TSource">源类型.</typeparam>
+        /// <typeparam name="TTarget">目标类型.</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        /// <param name="mapperName">mapper别名</param>
+        /// <returns></returns>
+        public static IQueryable<TTarget> Select<TSource, TTarget>(this IQueryable<TSource> query, string mapperName) where TSource : class where TTarget : class
+        {
+            return GetSelect<TSource, TTarget>(query, mapperName);
+        }
+
+        /// <summary>
+        /// 根据谓词过滤一系列值。
+        /// </summary>
+        /// <typeparam name="TSource">源类型</typeparam>
+        /// <typeparam name="TTarget">目标类型</typeparam>
+        /// <param name="query">分类化的序列值</param>
+        /// <param name="predicate">用于根据条件测试每个元素的功能。</param>
+        /// <returns></returns>
+        public static IQueryable<TTarget> Where<TSource, TTarget>(this IQueryable<TTarget> query, Expression<Func<TSource, bool>> predicate)
+        {
+            return Queryable.Where(query, predicate.ConvertTo<TSource, TTarget>());
+        }
+
+        private static TQueryable CreateSortedMethodCall<TSource, TTarget, TQueryable>(IQueryable<TSource> query, string methodName, string sortedPropertySourceName) where TSource : class where TTarget : class where TQueryable : class, IQueryable<TSource>
+        {
+            MapperConfiguration<TSource, TTarget> mapper = ExpressionMapper.GetMapper<TSource, TTarget>();
+            var prop = mapper.GetLambdaDest(sortedPropertySourceName);
+            var lambda = mapper.GetSortedExpression(sortedPropertySourceName);
+            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[]
+            {
+                typeof(TSource),
+                prop.Type
+            }, query.Expression, Expression.Quote(lambda));
+            return query.Provider.CreateQuery<TSource>(resultExp) as TQueryable;
+        }
+
+        private static IQueryable<TTarget> GetSelect<TSource, TTarget>(IQueryable<TSource> query, string mapperName) where TSource : class where TTarget : class
+        {
+            // 不需要mapper
+            if (typeof(TSource) == typeof(TTarget))
+            {
+                return (IQueryable<TTarget>)query;
+            }
+            return query.Select(ExpressionMapper.GetMapper<TSource, TTarget>(mapperName).GetLambdaExpression());
+        }
+    }
+}

+ 34 - 0
Masuit.Tools/Mapping/Helper/MapperHelper.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping.Helper
+{
+    /// <summary>
+    /// mapper帮助类
+    /// </summary>
+    internal static class MapperHelper
+    {
+        /// <summary>
+        /// 获取类型的默认值。
+        /// </summary>
+        /// <param name="typeObject">对象类型</param>
+        internal static object GetDefaultValue(Type typeObject)
+        {
+            object defaultValue = null;
+            // 对于值类型(例如Integer),必须将对象实例化为具有其默认值。
+            if (typeObject.BaseType == typeof(ValueType))
+            {
+                NewExpression exp = Expression.New(typeObject);
+                LambdaExpression lambda = Expression.Lambda(exp);
+                Delegate constructor = lambda.Compile();
+                defaultValue = constructor.DynamicInvoke();
+            }
+            if (typeObject.IsEnum)
+            {
+                defaultValue = Enum.Parse(typeObject, Enum.GetNames(typeObject)[0]);
+            }
+
+            return defaultValue;
+        }
+    }
+}

+ 64 - 0
Masuit.Tools/Mapping/Helper/TypeSystem.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+
+namespace Masuit.Tools.Mapping.Helper
+{
+    internal static class TypeSystem
+    {
+        internal static Type GetElementType(Type seqType)
+        {
+            Type ienum = FindIEnumerable(seqType);
+            if (ienum == null)
+            {
+                return seqType;
+            }
+
+            return ienum.GetGenericArguments()[0];
+        }
+
+        private static Type FindIEnumerable(Type seqType)
+        {
+            if (seqType == null || seqType == typeof(string))
+            {
+                return null;
+            }
+
+            if (seqType.IsArray)
+            {
+                return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
+            }
+
+            if (seqType.IsGenericType)
+            {
+                foreach (Type arg in seqType.GetGenericArguments())
+                {
+                    Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
+                    if (ienum.IsAssignableFrom(seqType))
+                    {
+                        return ienum;
+                    }
+                }
+            }
+
+            Type[] ifaces = seqType.GetInterfaces();
+
+            if (ifaces != null && ifaces.Length > 0)
+            {
+                foreach (Type iface in ifaces)
+                {
+                    Type ienum = FindIEnumerable(iface);
+                    if (ienum != null)
+                    {
+                        return ienum;
+                    }
+                }
+            }
+
+            if (seqType.BaseType != null && seqType.BaseType != typeof(object))
+            {
+                return FindIEnumerable(seqType.BaseType);
+            }
+            return null;
+        }
+    }
+}

+ 0 - 40
Masuit.Tools/Mapping/MapClass.cs

@@ -1,40 +0,0 @@
-using System.Collections.Generic;
-
-namespace Masuit.Tools.Mapping
-{
-    /// <summary>
-    /// 映射操作类
-    /// </summary>
-    public static class MapClass
-    {
-        /// <summary>
-        /// 将对象TSource转换为TDest
-        /// </summary>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static TDest Map<TSource, TDest>(this TSource source) where TDest : class where TSource : class => ExpressionGenericMapper<TSource, TDest>.Map(source);
-
-        /// <summary>
-        /// 集合元素映射
-        /// </summary>
-        /// <param name="sources"></param>
-        /// <returns></returns>
-        public static List<TDest> MapList<TSource, TDest>(this IEnumerable<TSource> sources) where TDest : class where TSource : class => ExpressionGenericMapper<TSource, TDest>.MapList(sources);
-
-        /// <summary>
-        /// 将对象TSource的值赋给给TDest
-        /// </summary>
-        /// <param name="source"></param>
-        /// <param name="target"></param>
-        public static void MapTo<TSource, TDest>(this TSource source, TDest target) where TSource : class where TDest : class => ExpressionGenericMapper<TSource, TDest>.Map(source, target);
-
-        /// <summary>
-        /// 复制一个新对象
-        /// </summary>
-        /// <typeparam name="TSource"></typeparam>
-        /// <param name="source"></param>
-        /// <returns></returns>
-        public static TSource Copy<TSource>(this TSource source) where TSource : class => ExpressionGenericMapper<TSource, TSource>.Copy(source);
-
-    }
-}

+ 0 - 50
Masuit.Tools/Mapping/MapperTools.cs

@@ -1,50 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Concurrent;
-using System.Linq;
-using System.Linq.Expressions;
-
-namespace Masuit.Tools
-{
-    /// <summary>
-    /// 工具类
-    /// </summary>
-    internal static class MapperTools
-    {
-        private static readonly Type _typeString = typeof(string);
-
-        private static readonly Type _typeIEnumerable = typeof(IEnumerable);
-
-        private static readonly ConcurrentDictionary<Type, Func<object>> _ctors = new ConcurrentDictionary<Type, Func<object>>();
-
-        /// <summary>
-        /// 判断是否是string以外的引用类型
-        /// </summary>
-        /// <returns>True:是string以外的引用类型,False:不是string以外的引用类型</returns>
-        public static bool IsRefTypeExceptString(Type type) => !type.IsValueType && type != _typeString;
-
-        /// <summary>
-        /// 判断是否是string以外的可遍历类型
-        /// </summary>
-        /// <returns>True:是string以外的可遍历类型,False:不是string以外的可遍历类型</returns>
-        public static bool IsIEnumerableExceptString(Type type) => _typeIEnumerable.IsAssignableFrom(type) && type != _typeString;
-
-        /// <summary>
-        /// 创建指定类型实例
-        /// </summary>
-        /// <param name="type">类型信息</param>
-        /// <returns>指定类型的实例</returns>
-        public static object CreateNewInstance(Type type) => _ctors.GetOrAdd(type, t => Expression.Lambda<Func<object>>(Expression.New(t)).Compile())();
-
-        public static bool IsNullableType(Type type)
-        {
-            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
-        }
-
-        public static bool IsEnumerable(Type type)
-        {
-            return type.IsArray || type.GetInterfaces().Any(x => x == typeof(ICollection) || x == typeof(IEnumerable));
-        }
-
-    }
-}

+ 0 - 18
Masuit.Tools/Mapping/UnsupportedTypeException.cs

@@ -1,18 +0,0 @@
-using System;
-
-namespace Masuit.Tools
-{
-    /// <summary>
-    /// 对尚不支持的类型进行拷贝时抛出的异常
-    /// </summary>
-    public class UnsupportedTypeException : Exception
-    {
-        /// <summary>
-        /// 用指定的类型初始化 DeepCopier.UnsupportedTypeException 类的新实例
-        /// </summary>
-        /// <param name="type">暂不支持的类型信息</param>
-        public UnsupportedTypeException(Type type) : base($"类型 [{type.Name}] 尚未实现支持!")
-        {
-        }
-    }
-}

+ 26 - 0
Masuit.Tools/Mapping/Visitor/ChangParameterExpressionVisitor.cs

@@ -0,0 +1,26 @@
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping.Visitor
+{
+    internal class ChangParameterExpressionVisitor : ExpressionVisitor
+    {
+        private readonly Expression[] _parameter;
+        internal ChangParameterExpressionVisitor(params Expression[] parameter)
+        {
+            _parameter = parameter;
+        }
+
+        protected override Expression VisitParameter(ParameterExpression node)
+        {
+            if (node != null)
+            {
+                Expression returnParameter = _parameter.FirstOrDefault(x => x.Type == node.Type);
+                if (returnParameter != null)
+                    return returnParameter;
+            }
+            return node;
+        }
+
+    }
+}

+ 109 - 0
Masuit.Tools/Mapping/Visitor/ConverterExpressionVisitor.cs

@@ -0,0 +1,109 @@
+using Masuit.Tools.Mapping.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping.Visitor
+{
+    /// <summary>
+    /// 将表达式从源转换为目标的访问者表达式
+    /// </summary>
+    public class ConverterExpressionVisitor : ExpressionVisitor
+    {
+        private readonly Dictionary<Expression, Expression> _parameterMap;
+        private readonly Type _destinationType;
+        private MapperConfigurationBase _mapper;
+
+
+        public ConverterExpressionVisitor(Dictionary<Expression, Expression> parameterMap, Type typeDestination)
+        {
+            _parameterMap = parameterMap;
+            _destinationType = typeDestination;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="node">访问表达式树</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        protected override Expression VisitParameter(ParameterExpression node)
+        {
+            if (!_parameterMap.TryGetValue(node, out var found))
+            {
+                found = Expression.Parameter(_destinationType, "dest");
+            }
+
+            return found;
+        }
+
+        /// <summary>
+        /// 将表达式分布在此类中更专业的访问方法之一。
+        /// </summary>
+        /// <param name="node">访问表达式树</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        public override Expression Visit(Expression node)
+        {
+            if (node != null)
+            {
+                Expression expression;
+                switch (node.NodeType)
+                {
+                    case ExpressionType.Lambda:
+                        expression = base.Visit((node as LambdaExpression).Body);
+                        break;
+                    default:
+                        expression = base.Visit(node);
+                        break;
+                }
+                return expression;
+            }
+            return node;
+        }
+
+        /// <summary>
+        /// 访问子表达式树
+        /// </summary>
+        /// <param name="node">访问表达式树</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        protected override Expression VisitMember(MemberExpression node)
+        {
+            var expr = Visit(node.Expression);
+            if (expr != null && expr.Type != node.Type)
+            {
+                if (_mapper == null)
+                {
+                    _mapper = ExpressionMapper.GetMapper(node.Member.DeclaringType, _destinationType);
+                }
+                Expression expDest;
+                // 认为原始类是简单属性(不是子对象)。
+                if (!expr.Type.IsValueType && expr.Type != typeof(string) && expr.NodeType != ExpressionType.Parameter && expr.NodeType != ExpressionType.Constant)
+                {
+                    var subExp = ExpressionMapper.GetMapper(node.Member.DeclaringType, expr.Type);
+                    expDest = subExp.GetLambdaDest(node.Member.Name);
+                    return AnalyseDestExpression(expr, expDest);
+                }
+                expDest = _mapper.GetLambdaDest(node.Member.Name);
+                if (expDest != null)
+                {
+                    return AnalyseDestExpression(expr, expDest);
+                }
+            }
+            return base.VisitMember(node);
+        }
+
+        private Expression AnalyseDestExpression(Expression expr, Expression expDest)
+        {
+            if (expDest.NodeType == ExpressionType.MemberAccess)
+            {
+                return Expression.MakeMemberAccess(expr, (expDest as MemberExpression).Member);
+            }
+            return base.Visit(expDest);
+        }
+    }
+}

+ 203 - 0
Masuit.Tools/Mapping/Visitor/MapperExpressionVisitor.cs

@@ -0,0 +1,203 @@
+using Masuit.Tools.Mapping.Helper;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Masuit.Tools.Mapping.Visitor
+{
+    public class MapperExpressionVisitor : ExpressionVisitor
+    {
+        private bool _checkNull;
+        readonly Stack<MemberExpression> _membersToCheck;
+
+        internal Expression Parameter { get; }
+
+        public MapperExpressionVisitor(Expression paramClassSource)
+        {
+            Parameter = paramClassSource;
+            _membersToCheck = new Stack<MemberExpression>();
+        }
+
+        /// <summary>
+        /// 将表达式分布在此类中更专一的访问方法之一。
+        /// </summary>
+        /// <param name="node">访问表达式树</param>
+        /// <param name="checkIfNullity">检查null值</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        public Expression Visit(Expression node, bool checkIfNullity = false)
+        {
+            _checkNull = checkIfNullity;
+            if (node == null)
+            {
+                return node;
+            }
+
+            if (_checkNull)
+            {
+                Expression result;
+                switch (node.NodeType)
+                {
+                    case ExpressionType.MemberAccess:
+                        result = VisitMember(node as MemberExpression);
+                        break;
+                    case ExpressionType.Parameter:
+                        result = VisitParameter(node as ParameterExpression);
+                        break;
+                    case ExpressionType.Convert:
+                        result = VisitMember((node as UnaryExpression).Operand as MemberExpression);
+                        break;
+                    case ExpressionType.Lambda:
+                        LambdaExpression lambda = ((LambdaExpression)node);
+                        // 子表达式树
+                        if (lambda.Body.NodeType != ExpressionType.Lambda)
+                        {
+                            result = Visit(lambda.Body);
+                        }
+                        else
+                        {
+                            return lambda;
+                        }
+
+                        break;
+                    default:
+                        result = base.Visit(node);
+                        break;
+                }
+
+                bool isFirst = true;
+                Expression previousExpression = null;
+                if (_membersToCheck.Count > 1)
+                {
+                    // 在分配值之前测试所有子对象。例如:source.SubClass.SubClass2.MyProperty。是哪个会给:
+                    // source.SubClass!= null? source.SubClass.SubClass2!= null? source.SubClass.SubClass2.MyProperty:DefaultValueOfProperty:DefaultValueOfProperty
+                    foreach (MemberExpression item in _membersToCheck)
+                    {
+                        if (!isFirst) // 不要测试该属性的值。
+                        {
+                            object defaultValue = MapperHelper.GetDefaultValue(item.Type);
+
+                            // 创建默认值的验证。
+                            Expression notDefaultValue = Expression.NotEqual(item, Expression.Constant(defaultValue, item.Type));
+                            Expression conditional = null;
+                            // 它创建了包含上述条件的条件。
+                            if (previousExpression != null)
+                            {
+                                object defaultPreviousValue = MapperHelper.GetDefaultValue(previousExpression.Type);
+                                conditional = Expression.Condition(notDefaultValue, previousExpression, Expression.Constant(defaultPreviousValue, previousExpression.Type));
+                            }
+
+                            // 它会影响新创建的条件,这些条件将成为之前的条件。
+                            previousExpression = conditional;
+                        }
+                        else // 属性
+                        {
+                            previousExpression = item;
+                            isFirst = false;
+                        }
+                    }
+
+                    return previousExpression;
+                }
+
+                // 不需要递归的元素。
+                if (_membersToCheck.Count == 1)
+                {
+                    var item = _membersToCheck.Peek();
+                    object defaultValue = MapperHelper.GetDefaultValue(item.Type);
+                    // 创建默认值的验证。
+                    Expression notDefaultValue = Expression.NotEqual(item, Expression.Constant(defaultValue, item.Type));
+                    Expression conditional = Expression.Condition(notDefaultValue, item, Expression.Constant(defaultValue, item.Type));
+
+                    return conditional;
+                }
+
+                return result;
+            }
+
+            // 默认返回(更改参数),删除lambda表达式的验证。
+            if ((node.NodeType == ExpressionType.Lambda))
+            {
+                LambdaExpression lambda = ((LambdaExpression)node);
+                // 子表达式树
+                if (lambda.Body.NodeType != ExpressionType.Call)
+                {
+                    return base.Visit(lambda.Body);
+                }
+
+                return lambda;
+            }
+
+            return base.Visit(node);
+        }
+
+        /// <summary>
+        /// 访问表达式树
+        /// </summary>
+        /// <param name="node">表达式树节点</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        protected override Expression VisitParameter(ParameterExpression node)
+        {
+            return Parameter;
+        }
+
+        /// <summary>
+        /// 访问子表达式树
+        /// </summary>
+        /// <param name="node">表达式树节点</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        protected override Expression VisitMember(MemberExpression node)
+        {
+            if (node == null)
+            {
+                return node;
+            }
+
+            if (node.Member.ReflectedType != Parameter.Type)
+            {
+                var exp = Visit(node.Expression);
+                return Expression.MakeMemberAccess(exp, node.Member);
+            }
+
+            MemberExpression memberAccessExpression = (MemberExpression)base.VisitMember(node);
+
+            // 稍后处理
+            if (memberAccessExpression != null && _checkNull)
+            {
+                // 如果最后一个成员是第一次访问,那么每次都得回去,当前的插入成员位于列表的第一行以更改顺序。
+                _membersToCheck.Push(memberAccessExpression);
+            }
+
+            return memberAccessExpression;
+        }
+
+        /// <summary>
+        ///  访问子表达式树
+        /// </summary>
+        /// <param name="node">表达式树节点</param>
+        /// <returns>
+        /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。
+        /// </returns>
+        protected override Expression VisitUnary(UnaryExpression node)
+        {
+            if (node != null)
+            {
+                if (node.Operand.NodeType == ExpressionType.MemberAccess)
+                {
+                    return VisitMember(node.Operand as MemberExpression);
+                }
+
+                if (node.NodeType == ExpressionType.Convert)
+                {
+                    return Visit(node.Operand);
+                }
+            }
+
+            return node;
+        }
+    }
+}

+ 35 - 0
Masuit.Tools/Mapping/Visitor/PropertiesVisitor.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Masuit.Tools.Mapping.Visitor
+{
+    internal class PropertiesVisitor : ExpressionVisitor
+    {
+        private readonly List<PropertyInfo> _propertiesOfExpression;
+
+        private readonly Type _typeReference;
+
+        internal PropertiesVisitor(Type typeReference)
+        {
+            _typeReference = typeReference;
+            _propertiesOfExpression = new List<PropertyInfo>();
+        }
+
+        protected override Expression VisitMember(MemberExpression node)
+        {
+            if (_typeReference == node.Member.DeclaringType)
+            {
+                _propertiesOfExpression.Add(node.Member as PropertyInfo);
+            }
+            return base.VisitMember(node);
+        }
+
+        internal List<PropertyInfo> GetProperties(Expression expression)
+        {
+            Visit(expression);
+            return _propertiesOfExpression;
+        }
+    }
+}

+ 25 - 5
Masuit.Tools/Masuit.Tools.csproj

@@ -103,8 +103,6 @@
     <Compile Include="Files\ClassZip.cs" />
     <Compile Include="Files\SharpZip.cs" />
     <Compile Include="Files\WinrarHelper.cs" />
-    <Compile Include="Mapping\EnumerableCopier.cs" />
-    <Compile Include="Mapping\ExpressionGenericMapper.cs" />
     <Compile Include="Extensions.cs" />
     <Compile Include="Files\SevenZipCompressor.cs" />
     <Compile Include="Files\ExtensionAttach.cs" />
@@ -125,9 +123,31 @@
     <Compile Include="Logging\LogInfo.cs" />
     <Compile Include="Logging\LogLevel.cs" />
     <Compile Include="Logging\LogManager.cs" />
-    <Compile Include="Mapping\MapClass.cs" />
-    <Compile Include="Mapping\MapperTools.cs" />
-    <Compile Include="Mapping\UnsupportedTypeException.cs" />
+    <Compile Include="Mapping\Copier.cs" />
+    <Compile Include="Mapping\Core\CreateConfig.cs" />
+    <Compile Include="Mapping\Core\MapperConfiguration.cs" />
+    <Compile Include="Mapping\Core\MapperConfigurationBase.cs" />
+    <Compile Include="Mapping\Core\MapperConfigurationCollectionContainer.cs" />
+    <Compile Include="Mapping\Core\PropertiesNotMapped.cs" />
+    <Compile Include="Mapping\Core\TypePairMapper.cs" />
+    <Compile Include="Mapping\Exceptions\MapperExceptionBase.cs" />
+    <Compile Include="Mapping\Exceptions\MapperExistException.cs" />
+    <Compile Include="Mapping\Exceptions\MapperNotInitializedException.cs" />
+    <Compile Include="Mapping\Exceptions\NoActionAfterMappingException.cs" />
+    <Compile Include="Mapping\Exceptions\NoFoundMapperException.cs" />
+    <Compile Include="Mapping\Exceptions\NotSameTypePropertyException.cs" />
+    <Compile Include="Mapping\Exceptions\PropertyNoExistException.cs" />
+    <Compile Include="Mapping\Exceptions\ReadOnlyPropertyException.cs" />
+    <Compile Include="Mapping\ExpressionCpoier.cs" />
+    <Compile Include="Mapping\ExpressionMapper.cs" />
+    <Compile Include="Mapping\Extensions\ExpressionExtentions.cs" />
+    <Compile Include="Mapping\Extensions\QueryableExtentions.cs" />
+    <Compile Include="Mapping\Helper\MapperHelper.cs" />
+    <Compile Include="Mapping\Helper\TypeSystem.cs" />
+    <Compile Include="Mapping\Visitor\ChangParameterExpressionVisitor.cs" />
+    <Compile Include="Mapping\Visitor\ConverterExpressionVisitor.cs" />
+    <Compile Include="Mapping\Visitor\MapperExpressionVisitor.cs" />
+    <Compile Include="Mapping\Visitor\PropertiesVisitor.cs" />
     <Compile Include="Media\ThumbnailCutMode.cs" />
     <Compile Include="Models\BaiduIP.cs" />
     <Compile Include="Models\IspInfo.cs" />

+ 2 - 2
Masuit.Tools/Properties/AssemblyInfo.cs

@@ -36,7 +36,7 @@ using System.Runtime.InteropServices;
 // 方法是按如下所示使用“*”: :
 // [assembly: AssemblyVersion("1.0.*")]
 
-[assembly: AssemblyVersion("2.2.3.5")]
-[assembly: AssemblyFileVersion("2.2.3.5")]
+[assembly: AssemblyVersion("2.2.4.0")]
+[assembly: AssemblyFileVersion("2.2.4.0")]
 [assembly: NeutralResourcesLanguage("zh-CN")]