性能接近硬编码,推荐使用
/// <summary> /// 高性能对象映射 /// </summary> /// <typeparam name="TSource"></typeparam> /// <typeparam name="TTarget"></typeparam> public static class ExpressionMapper<TSource, TTarget> where TSource : class where TTarget : class { private static readonly ConcurrentDictionary<string, Func<TSource, TTarget>> FUNC_CACHE = new ConcurrentDictionary<string, Func<TSource, TTarget>>(); private static readonly ConcurrentDictionary<Type, PropertyInfo[]> TYPE_CACHE = new ConcurrentDictionary<Type, PropertyInfo[]>(); /// <summary> /// 对象映射 /// </summary> /// <returns></returns> public static TTarget Trans(TSource source) { if (source == null) { return null; } var sourceType = typeof(TSource); var targetType = typeof(TTarget); string cacheName = $"cache_{typeof(TSource).FullName}_{typeof(TTarget).FullName}"; Func<TSource, TTarget> func = FUNC_CACHE.GetOrAdd(cacheName, key => { //构造 p=> var parameterExpression = Expression.Parameter(sourceType, "p"); var memberBindingList = new List<MemberBinding>(); foreach (var sourceItem in sourceType.GetProperties()) { var targetItem = targetType.GetProperty(sourceItem.Name); if (targetItem == null || sourceItem.PropertyType != targetItem.PropertyType || !targetItem.CanWrite) { continue; } var property = Expression.Property(parameterExpression, sourceItem); var memberBinding = Expression.Bind(targetItem, property); memberBindingList.Add(memberBinding); } var memberInitExpression = Expression.MemberInit(Expression.New(targetType), memberBindingList); var lambda = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, parameterExpression); Console.WriteLine(lambda); return lambda.Compile(); }); return func(source); } /// <summary> /// 列表映射 /// </summary> /// <param name="tSourceList"></param> /// <returns></returns> public static List<TTarget> Trans(IEnumerable<TSource> tSourceList) { List<TTarget> outList = new List<TTarget>(); if (tSourceList != null) { foreach (var inItem in tSourceList) { outList.Add(Trans(inItem)); } } return outList; } /// <summary> /// 更新现有对象,指定要更新的属性 /// </summary> /// <param name="source"></param> /// <param name="target"></param> public static void TryUpdateModel(TSource source, TTarget target, params Expression<Func<TSource, object>>[] includeExps) { string[] includePropertyNames = includeExps != null ? GetPropertyNames<TSource>(includeExps) : null; TryUpdateModel(source, target, includePropertyNames); } /// <summary> /// 更新现有对象,指定要更新的属性 /// </summary> /// <param name="source"></param> /// <param name="target"></param> public static void TryUpdateModel(TSource source, TTarget target, params string[] includeProperties) { //TTarget tOutNew = Trans(source); if (target != null) { var inProperties = GetProperties(typeof(TSource)); var outProperties = GetProperties(typeof(TTarget)); PropertyInfo inProp = null; object inValue = null; foreach (var outProp in outProperties) { if (includeProperties?.Length > 0 && !includeProperties.Contains(outProp.Name)) { continue; } inProp = inProperties.FirstOrDefault(p => p.Name.Equals(outProp.Name, StringComparison.CurrentCultureIgnoreCase)); inValue = inProp.GetValue(source); if (inValue != null) { outProp.SetValue(target, inValue); } } } } /// <summary> /// 更新现有对象,指定要排除的属性 /// </summary> /// <param name="source"></param> /// <param name="target"></param> public static void TryUpdateModelEx(TSource source, TTarget target, params Expression<Func<TSource, object>>[] excludeExps) { string[] excludePropertyNames = excludeExps != null ? GetPropertyNames<TSource>(excludeExps) : null; TryUpdateModelEx(source, target, excludePropertyNames); } /// <summary> /// 更新现有对象,指定要排除的属性 /// </summary> /// <param name="source"></param> /// <param name="target"></param> public static void TryUpdateModelEx(TSource source, TTarget target, params string[] excludePropertyNames) { //TTarget tOutNew = Trans(source); if (target != null) { var inProperties = GetProperties(typeof(TSource)); var outProperties = GetProperties(typeof(TTarget)); PropertyInfo inProp = null; object inValue = null; foreach (var outProp in outProperties) { if (excludePropertyNames?.Length > 0 && excludePropertyNames.Contains(outProp.Name)) { continue; } inProp = inProperties.FirstOrDefault(p => p.Name.Equals(outProp.Name, StringComparison.CurrentCultureIgnoreCase)); if (inProp != null) { inValue = inProp.GetValue(source); if (inValue != null) { outProp.SetValue(target, inValue); } } } } } private static PropertyInfo[] GetProperties(Type t) { return TYPE_CACHE.GetOrAdd(t, (k) => { return t.GetProperties(); }); } private static string[] GetPropertyNames<T>(params Expression<Func<T, object>>[] exps) { string[] props = new string[exps.Length]; for (int i = 0; i < exps.Length; i++) { props[i] = GetPropertyName(exps[i]); } return props; } private static readonly ConcurrentDictionary<Type, string> EXPRESSION_CACHE = new ConcurrentDictionary<Type, string>(); private static string GetPropertyName<T>(Expression<Func<T, object>> expr) { return EXPRESSION_CACHE.GetOrAdd(expr.GetType(), t => { string rtn = null; if (expr.Body is UnaryExpression) { rtn = ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name; } else if (expr.Body is MemberExpression) { rtn = ((MemberExpression)expr.Body).Member.Name; } else if (expr.Body is ParameterExpression) { rtn = ((ParameterExpression)expr.Body).Type.Name; } return rtn; }); } }
客户端:
//1 var peopleDTO1 = ExpressionMapper<People, PeopleDTO>.Trans(p); //2绑定 var peopleDTO2 = new PeopleDTO() { Name="",Birthday = DateTime.Now.AddYears(1) }; ExpressionMapper<People, PeopleDTO>.TryUpdateModel(p, peopleDTO2,nameof(p.Name));