瀏覽代碼

表达式树实现对象映射

懒得勤快 6 年之前
父節點
當前提交
a4cb48af2a

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

@@ -0,0 +1,105 @@
+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;
+        }
+    }
+}

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

@@ -0,0 +1,470 @@
+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
+{
+    internal static class ExpressionGenericMapper<TSource, TDest> where TSource : class where TDest : class
+    {
+        // 缓存委托
+        private static Func<TSource, TDest> MapFunc { get; set; }
+        private static Action<TSource, TDest> MapAction { get; set; }
+        private static Func<TSource, TDest> _copyFunc;
+        private static Action<TSource, TDest> _copyAction;
+
+        /// <summary>
+        /// 将对象TSource转换为TDest
+        /// </summary>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static TDest Map(TSource source)
+        {
+            if (MapFunc == null)
+            {
+                MapFunc = GetMapFunc();
+            }
+
+            return MapFunc(source);
+        }
+
+        public static List<TDest> MapList(IEnumerable<TSource> sources)
+        {
+            if (MapFunc == null)
+            {
+                MapFunc = GetMapFunc();
+            }
+
+            return sources.Select(MapFunc).ToList();
+        }
+
+        /// <summary>
+        /// 将对象TSource的值赋给给TDest
+        /// </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 (IsEnumerable(sourceType) || 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 (IsNullableType(sourceItem.PropertyType) && !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 (!IsNullableType(sourceItem.PropertyType) && 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));
+
+            //构造回调 Mapper<TSource, TDest>.Map()
+            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));
+
+            //构造回调 Mapper<TSource, TDest>.MapList()
+            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 (IsEnumerable(sourceType) || IsEnumerable(targetType))
+            {
+                throw new NotSupportedException("Enumerable types are not supported,please use MapList method.");
+            }
+
+            //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 (IsNullableType(sourceItem.PropertyType) && !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 (!IsNullableType(sourceItem.PropertyType) && 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();
+        }
+
+        private static bool IsNullableType(Type type)
+        {
+            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
+        }
+
+        private static bool IsEnumerable(Type type)
+        {
+            return type.IsArray || type.GetInterfaces().Any(x => x == typeof(ICollection) || x == typeof(IEnumerable));
+        }
+
+        /// <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);
+                    if (sourcePropInfo is null)
+                    {
+                        continue;
+                    }
+
+                    Type sourcePropType = sourcePropInfo?.PropertyType;
+                    Type targetPropType = targetPropInfo.PropertyType;
+
+                    // 只在满足以下三个条件的情况下进行拷贝
+                    // 1.源属性类型和目标属性类型一致
+                    // 2.源属性可读
+                    // 3.目标属性可写
+                    if (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
+        });
+    }
+}

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

@@ -0,0 +1,44 @@
+using System.Collections.Generic;
+
+namespace Masuit.Tools.Mapping
+{
+    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>.Map(source);
+
+        /// <summary>
+        /// 复制一个新集合
+        /// </summary>
+        /// <typeparam name="TSource"></typeparam>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static List<TSource> Copy<TSource>(this IEnumerable<TSource> source) where TSource : class => ExpressionGenericMapper<TSource, TSource>.MapList(source);
+    }
+}

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

@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+using System.Collections.Concurrent;
+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())();
+    }
+}

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

@@ -0,0 +1,18 @@
+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[{type.Name}] has not been supported yet.")
+        {
+        }
+    }
+}