使用C#表达式树为两个对象的相同属性赋值

 //缓存表达式树
         private static Dictionary objCache = new Dictionary();
 
         /// 
         /// 使用表达式树为两个对象的相同属性赋值
         /// 
         /// 源对象
         /// 目标对象
         /// 源实例
         /// 目标实例
         private static TOut ObjCopyByExpressionTree(TIn tIn)
         {
             string key = string.Format("Key_{0}_To_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
             if (!objCache.ContainsKey(key))
             {
                 //表示一个命名的参数表达式
                 //创建一个 System.Linq.Expressions.ParameterExpression 节点,该节点可用于标识表达式树中的参数或变量
                 //   type:
                 //     参数或变量的类型。
                 //
                 //   name:
                 //     仅用于调试或打印目的的参数或变量的名称
                 ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "parameter");
 
                 //提供表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化
                 List memberBindingList = new List();
 
                 foreach (var item in typeof(TOut).GetProperties())
                 {
                     //表示访问字段或属性
                     //   expression:
                     //     要将 System.Linq.Expressions.Expression 属性设置为与其相等的 System.Linq.Expressions.MemberExpression.Expression。
                     //     对于静态属性,这可以为 null。
                     //
                     //   property:
                     //     要将 System.Reflection.PropertyInfo 属性设置为与其相等的 System.Linq.Expressions.MemberExpression.Member。
                     MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
 
                     //提供表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化。
                     MemberBinding memberBinding = Expression.Bind(item, property);
 
                     memberBindingList.Add(memberBinding);
                 };
 
                 //表示调用构造函数并初始化新对象的一个或多个成员。
                 MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
 
                 //将强类型化的 Lambda 表达式表示为表达式树形式的数据结构
                 Expression> lambda = Expression.Lambda>(memberInitExpression, new ParameterExpression[] { parameterExpression });
 
                 //封装一个方法,该方法具有一个参数,且返回由 TResult 参数指定的类型的值
                 //编译表达式树由描述为可执行代码的 lambda 表达式,并生成一个委托,表示 lambda 表达式
                 Func func = lambda.Compile();
 
                 objCache[key] = func;
             }
             return ((Func)objCache[key])(tIn);
         }
private static void ExpTrans(ILoginUser loginUser, ref IVoState voState, Dictionary mappingDic = null)
        {
            List memberBindingList = new List();
            ParameterExpression parameterExpression = Expression.Parameter(typeof(ILoginUser), "p");
            //目标
            var targetAllPropertys = voState.GetType().GetProperties();
            var targetparamNames = mappingDic ?? new Dictionary(targetAllPropertys.Select(t => new KeyValuePair(t.Name, t.Name)));
            foreach (var item in targetparamNames)
            {
                var itemProperty = targetAllPropertys.FirstOrDefault(t => t.Name == item.Key && t.CanWrite);
                if (itemProperty == null)
                    continue;
                if (string.IsNullOrEmpty(item.Value) || loginUser.GetType().GetProperty(item.Value) == null)
                {
                    //来源不存在该对应的属性
                    if (itemProperty.PropertyType == typeof(string))
                        memberBindingList.Add(Expression.Bind(itemProperty, Expression.Constant(string.Empty)));
                    if (itemProperty.PropertyType == typeof(DateTime))
                        memberBindingList.Add(Expression.Bind(itemProperty, Expression.Constant(DateTime.Now, typeof(DateTime))));
                    if (itemProperty.PropertyType == typeof(Nullable))
                        memberBindingList.Add(Expression.Bind(itemProperty, Expression.Constant(DateTime.Now, typeof(Nullable))));
                    continue;
                }
                memberBindingList.Add(Expression.Bind(itemProperty, Expression.Property(parameterExpression, item.Value)));
            }
            if (memberBindingList.Any() == false)
                return;
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(voState.GetType()), memberBindingList.ToArray());
            Expression> lambda = Expression.Lambda>(memberInitExpression, new ParameterExpression[] { parameterExpression });
            voState = lambda.Compile().Invoke(loginUser);
        }
private static TTarget ExpTrans(TSource message, Func mappingPropery = null, Func bindConstantExpressionWhenNull = null) where TTarget : class, new()
        {
            mappingPropery ??= (t) => t;
            bindConstantExpressionWhenNull ??= (t) =>
            {
                if (t.PropertyType == typeof(string))
                    return Expression.Constant(string.Empty);
                if (t.PropertyType == typeof(DateTime))
                    return Expression.Constant(DateTime.Now, typeof(DateTime));
                if (t.PropertyType == typeof(Nullable))
                    return Expression.Constant(DateTime.Now, typeof(Nullable));
                return null;
            };
            var target = Expression.Parameter(typeof(TTarget));
            var source = Expression.Parameter(message.GetType());
            var sourceProps = message.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanRead).ToList();
            var targetPros = typeof(TTarget).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanWrite).ToList();
            List blocks = new(targetPros.Count);
            foreach (var mappPros in targetPros)
            {
                var sourceName = mappingPropery.Invoke(mappPros.Name);
                if (sourceProps.Any(t => t.Name == sourceName))
                {
                    blocks.Add(Expression.Assign(Expression.Property(target, mappPros), Expression.Property(source, sourceName)));
                    continue;
                }
                Expression constExpression = bindConstantExpressionWhenNull.Invoke(mappPros);
                if (constExpression == null)
                    continue;
                blocks.Add(Expression.Assign(Expression.Property(target, mappPros), constExpression));
            }
            var block = Expression.Block(blocks);
            var setter = Expression.Lambda>(block, target, source).Compile();
            TTarget target1 = new();
            setter.Invoke(target1, message);
            return target1;
        }

你可能感兴趣的:(c#,linq,开发语言)