这个方法在复制时有个前提条件,如果这个对象或者这个对象的各级域成员 是一个类,同时有没有提供一个无参数的构造函数的话,不能进行深度复制。原因很简单,没有默认构造函数,我没法创建这个对象的实例。这个克隆方法的难点主要在数组的克隆,特别是多维数组。目前测试到了四维数组都可以正常克隆。有兴趣的可以帮忙提提建议。在写这个功能时得到我同事的支持。
- /// <summary>
- /// 深度复制一个对象,obj和obj任意级别的域成员类型一定都要有一个无参数的构造函数
- /// </summary>
- /// <param name="obj">被复制的对象</param>
- /// <returns>复制出来的对象</returns>
- public static object CopyFrom(object obj)
- {
- if (obj == null) return null;
- Type type = obj.GetType();
- if (!type.IsClass)
- {//除了结构外所有的基本类型都是在这里直接返回
- if (TypeHelper.IsMathType(type)) return obj;
- else if (type == typeof(bool)) return obj;
- else if (type.IsEnum) return obj;
- else if (type == typeof(char)) return obj;
- }
- if (type == typeof(string)) return obj; //字符串直接返回
- //以下是处理对象、结构、数组三种类型
- if (type.IsArray) //数组处理
- {
- Array arr = (Array)obj;
- int[] lengths = new int[arr.Rank];
- for (int i = 0; i < arr.Rank; i++) lengths[i] = arr.GetLength(i);
- Type elementType = typeof(object);
- foreach (object element in arr)//获取数组基础元素类型
- {
- if (element == null) continue;
- elementType = element.GetType();
- break;
- }
- Array newArr = Array.CreateInstance(elementType, lengths);//创建新数组
- int dimension = lengths.Length;
- for (int i = 0; i < arr.Length; i++) //新数组赋值
- {
- int[] indics = new int[dimension];
- for (int j = 0; j < dimension; j++)
- {
- int rearLength = 1;
- int pureRearLength = 1;
- for (int k = j + 1; k < dimension; k++) pureRearLength = pureRearLength * lengths[k];
- for (int k = j; k < dimension; k++) rearLength = rearLength * lengths[k];
- int colIndex = (i - i / rearLength * rearLength) / pureRearLength;
- indics[j] = colIndex;
- }
- object oldValue = arr.GetValue(indics);
- object newValue = CopyFrom(oldValue);
- newArr.SetValue(newValue, indics);
- }
- return newArr;
- }
- //处理结构和对象
- object to = Activator.CreateInstance(type, true);
- FieldInfo[] fis = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- foreach (FieldInfo fi in fis)
- {
- object value = fi.GetValue(obj);
- object newValue = CopyFrom(value);
- fi.SetValue(to, newValue);
- }
- return to;
- }
- //=====================================类型辅助类================================================
- /// <summary>
- /// 类型处理的辅助方法管理类
- /// Written by Lodgue
- /// </summary>
- public class TypeHelper
- {
- private static Dictionary<Type, int> numberTypes = GetNumberTypes();
- private static Dictionary<Type, int> GetNumberTypes()
- {
- if (numberTypes == null)
- {
- numberTypes = new Dictionary<Type, int>();
- numberTypes.Add(typeof(int), 1);
- numberTypes.Add(typeof(long), 1);
- numberTypes.Add(typeof(short), 1);
- numberTypes.Add(typeof(byte), 1);
- numberTypes.Add(typeof(double), 3);
- numberTypes.Add(typeof(decimal), 3);
- numberTypes.Add(typeof(float), 3);
- numberTypes.Add(typeof(sbyte), 1);
- numberTypes.Add(typeof(ushort), 1);
- numberTypes.Add(typeof(uint), 1);
- numberTypes.Add(typeof(ulong), 1);
- }
- return numberTypes;
- }
- /// <summary>
- /// 判断一个类型是否是不含有小数的数值类型。
- /// int, long, short, byte, sbyte, ushort, uint, ulong等返回为true
- /// 其他所有类型返回false
- /// </summary>
- /// <param name="type">数据类型</param>
- /// <returns>int, long, short, byte, sbyte, ushort, uint, ulong等返回为true其他所有类型返回false</returns>
- public static bool IsNumber(Type type)
- {
- if (numberTypes.ContainsKey(type))
- {
- int numberType = numberTypes[type];
- return (numberType == 1);
- }
- else
- {
- return false;
- }
- }
- /// <summary>
- /// 判断一个类型是否是数学数值类型。
- /// int, long, short, byte, sbyte, ushort, uint, ulong,
- /// decimal, double,float都返回为true, 反之返回 false
- /// </summary>
- /// <param name="type">要判断的类型</param>
- /// <returns>数学数值类型返回为true, 反之返回false</returns>
- public static bool IsMathType(Type type)
- {
- return numberTypes.ContainsKey(type);
- }
- /// <summary>
- /// 判断一个数值类型是否位小数
- /// Float, Double, Decimal返回true,其他返回false
- /// </summary>
- /// <param name="type">要判断的类型<</param>
- /// <returns>Float, Double, Decimal返回true,其他返回false</returns>
- public static bool IsDecimal(Type type)
- {
- if (numberTypes.ContainsKey(type))
- {
- int numberType = numberTypes[type];
- return (numberType == 3);
- }
- else
- {
- return false;
- }
- }