| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 | 
							- 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
 
-         });
 
-     }
 
- }
 
 
  |