Ejemplo n.º 1
0
Archivo: Clone.cs Proyecto: jclown/test
        public static T DeepCopyByReflect <T>(T obj)
        {
            //如果是字符串或值类型则直接返回
            if (obj == null)
            {
                return(default(T));
            }
            var type = obj.GetType();

            if (obj is string || type.IsValueType)
            {
                return(obj);
            }
            //if (IsValueArrayType(type))
            if (type.IsArray)
            {
                var method  = EnumerableCopier.GetMethondInfo(type);
                var newItem = method.Invoke(null, new object[] { obj });
                return((T)newItem);
            }
            object retval = Activator.CreateInstance(obj.GetType());

            FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (FieldInfo field in fields)
            {
                try
                {
                    field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj)));
                }
                catch (Exception ex)
                {
                    ex.ToString();
                }
            }
            return((T)retval);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 新建目标类型实例,并将源对象的属性值拷贝至目标对象的对应属性
        /// </summary>
        /// <param name="source">源对象实例</param>
        /// <returns>深拷贝了源对象属性的目标对象实例</returns>
        public static TTarget Copy(TSource source)
        {
            if (source == null)
            {
                return(default(TTarget));
            }

            // 因为对于泛型类型而言,每次传入不同的泛型参数都会调用静态构造函数,所以可以通过这种方式进行缓存
            if (_copyFunc != null)
            {
                // 如果之前缓存过,则直接调用缓存的委托
                return(_copyFunc(source));
            }

            Type sourceType = typeof(TSource);
            Type targetType = typeof(TTarget);

            var paramExpr = Expression.Parameter(sourceType, nameof(source));

            Expression bodyExpr;

            // 如果对象可以遍历(目前只支持数组和ICollection<T>实现类)
            if (sourceType == targetType && Utils.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, BindingFlags.IgnoreCase);

                    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 (Utils.IsRefTypeExceptString(targetPropType))
                        {
                            // 进行递归
                            if (Utils.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, TTarget> >(bodyExpr, paramExpr);

            _copyFunc = lambdaExpr.Compile();
            return(_copyFunc(source));
        }