深度复制一个对象方法。利用反射机制,不使用Serialization,也不使用ICloneable接口

来源:互联网 发布:地图绘制软件 编辑:程序博客网 时间:2024/04/29 07:40
这个方法在复制时有个前提条件,如果这个对象或者这个对象的各级域成员 是一个类,同时有没有提供一个无参数的构造函数的话,不能进行深度复制。原因很简单,没有默认构造函数,我没法创建这个对象的实例。这个克隆方法的难点主要在数组的克隆,特别是多维数组。目前测试到了四维数组都可以正常克隆。有兴趣的可以帮忙提提建议。在写这个功能时得到我同事的支持。
  1.        /// <summary>
  2.         /// 深度复制一个对象,obj和obj任意级别的域成员类型一定都要有一个无参数的构造函数
  3.         /// </summary>
  4.         /// <param name="obj">被复制的对象</param>
  5.         /// <returns>复制出来的对象</returns>
  6.         public static object CopyFrom(object obj)
  7.         {
  8.             if (obj == nullreturn null;
  9.             Type type = obj.GetType();
  10.             if (!type.IsClass)
  11.             {//除了结构外所有的基本类型都是在这里直接返回
  12.                 if (TypeHelper.IsMathType(type)) return obj;
  13.                 else if (type == typeof(bool)) return obj;
  14.                 else if (type.IsEnum) return obj;
  15.                 else if (type == typeof(char)) return obj;
  16.             }            
  17.             if (type == typeof(string)) return obj; //字符串直接返回
  18.             //以下是处理对象、结构、数组三种类型            
  19.             if (type.IsArray) //数组处理
  20.             {
  21.                 Array arr = (Array)obj;
  22.                 int[] lengths = new int[arr.Rank];
  23.                 for (int i = 0; i < arr.Rank; i++) lengths[i] = arr.GetLength(i);
  24.                 Type elementType = typeof(object);
  25.                 foreach (object element in arr)//获取数组基础元素类型
  26.                 {
  27.                     if (element == nullcontinue;
  28.                     elementType = element.GetType();
  29.                     break;
  30.                 }
  31.                 Array newArr = Array.CreateInstance(elementType, lengths);//创建新数组
  32.                 int dimension = lengths.Length;
  33.                 for (int i = 0; i < arr.Length; i++) //新数组赋值
  34.                 {
  35.                     int[] indics = new int[dimension];
  36.                     for (int j = 0; j < dimension; j++)
  37.                     {
  38.                         int rearLength = 1;
  39.                         int pureRearLength = 1;
  40.                         for (int k = j + 1; k < dimension; k++) pureRearLength = pureRearLength * lengths[k];
  41.                         for (int k = j; k < dimension; k++) rearLength = rearLength * lengths[k];
  42.                         int colIndex = (i - i / rearLength * rearLength) / pureRearLength;
  43.                         indics[j] = colIndex;
  44.                     }
  45.                     object oldValue = arr.GetValue(indics);
  46.                     object newValue = CopyFrom(oldValue);
  47.                     newArr.SetValue(newValue, indics);
  48.                 }
  49.                 return newArr;
  50.             }
  51.             //处理结构和对象
  52.             object to = Activator.CreateInstance(type, true);
  53.             FieldInfo[] fis = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  54.             foreach (FieldInfo fi in fis)
  55.             {
  56.                 object value = fi.GetValue(obj);
  57.                 object newValue = CopyFrom(value);
  58.                 fi.SetValue(to, newValue);
  59.             }
  60.             return to;
  61.         }
  62. //=====================================类型辅助类================================================
  63. /// <summary>
  64.     /// 类型处理的辅助方法管理类
  65.     /// Written by Lodgue
  66.     /// </summary>
  67.     public class TypeHelper
  68.     {
  69.         private static Dictionary<Type, int> numberTypes = GetNumberTypes();
  70.         private static Dictionary<Type, int> GetNumberTypes()
  71.         { 
  72.             if (numberTypes == null)
  73.             {
  74.                 numberTypes = new Dictionary<Type, int>();
  75.                 numberTypes.Add(typeof(int), 1);
  76.                 numberTypes.Add(typeof(long), 1);
  77.                 numberTypes.Add(typeof(short), 1);
  78.                 numberTypes.Add(typeof(byte), 1);
  79.                 
  80.                 numberTypes.Add(typeof(double), 3);
  81.                 numberTypes.Add(typeof(decimal), 3);
  82.                 numberTypes.Add(typeof(float), 3);
  83.                 numberTypes.Add(typeof(sbyte), 1);
  84.                 numberTypes.Add(typeof(ushort), 1);
  85.                 numberTypes.Add(typeof(uint), 1);
  86.                 numberTypes.Add(typeof(ulong), 1);
  87.             }
  88.             return numberTypes;
  89.         }
  90.         /// <summary>
  91.         /// 判断一个类型是否是不含有小数的数值类型。
  92.         /// int, long, short, byte, sbyte, ushort, uint, ulong等返回为true
  93.         /// 其他所有类型返回false
  94.         /// </summary>
  95.         /// <param name="type">数据类型</param>
  96.         /// <returns>int, long, short, byte, sbyte, ushort, uint, ulong等返回为true其他所有类型返回false</returns>
  97.         public static bool IsNumber(Type type)
  98.         {
  99.              if (numberTypes.ContainsKey(type))
  100.             {
  101.                 int numberType = numberTypes[type];
  102.                 return (numberType == 1);
  103.             }
  104.             else
  105.             {
  106.               return false;
  107.             }
  108.         }
  109.         /// <summary>
  110.         /// 判断一个类型是否是数学数值类型。
  111.         /// int, long, short, byte, sbyte, ushort, uint, ulong,
  112.         /// decimal, double,float都返回为true, 反之返回 false        
  113.         /// </summary>
  114.         /// <param name="type">要判断的类型</param>
  115.         /// <returns>数学数值类型返回为true, 反之返回false</returns>
  116.         public static bool IsMathType(Type type)
  117.         {
  118.             return numberTypes.ContainsKey(type);            
  119.         }
  120.         /// <summary>
  121.         /// 判断一个数值类型是否位小数
  122.         /// Float, Double, Decimal返回true,其他返回false
  123.         /// </summary>
  124.         /// <param name="type">要判断的类型<</param>
  125.         /// <returns>Float, Double, Decimal返回true,其他返回false</returns>
  126.         public static bool IsDecimal(Type type)
  127.         {
  128.             if (numberTypes.ContainsKey(type))
  129.             {
  130.                 int numberType = numberTypes[type];
  131.                 return (numberType == 3);
  132.             }
  133.             else
  134.             {
  135.                 return false;
  136.             }
  137.         }