繼續上節的對象深拷貝,上節講了經過序列化和反序列化來實現深度拷貝,這一節咱們來說述一下第二種深度拷貝的方法,反射。經過反射來實現深度拷貝。this
反射主要是在運行時獲取對象的元信息,System.Reflection命名空間容許咱們在程序運行時來獲取對象的信息、建立已存在類的實例,也可以獲取對象的屬性和執行對象的方法。spa
下面我建立一個靜態的方法來接收任何類型的對象,並返回一個新對象的引用。code
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Reflection; 6 7 namespace ReflectionCopy 8 { 9 public class Utility 10 { 11 public static object CloneObject(object objsource) 12 { 13 //第一步獲取原對象的類型,並建立一個同類型的對象 14 Type typesource = objsource.GetType(); 15 16 object objTarget = Activator.CreateInstance(typesource); 17 18 //第二步獲取原對象的全部屬性 19 20 PropertyInfo[] propertyinfo = typesource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 21 22 //第三步將原對象的全部屬性賦給目標對象 23 24 foreach (PropertyInfo item in propertyinfo) 25 { 26 if (item.CanWrite) 27 { 28 29 //值類型,字符串,枚舉類型直接把值複製,不存在淺拷貝 雖然字符串是引用類型,可是字符串是不可變的,每次都是建立新的字符串對象,因此不存在淺拷貝 30 if (item.PropertyType.IsEnum || item.PropertyType.IsValueType || item.PropertyType.Equals(typeof(System.String))) 31 { 32 33 item.SetValue(objTarget, item.GetValue(objsource, null), null); 34 } 35 else 36 { 37 object objpropertyvalue = item.GetValue(objsource, null); 38 39 item.SetValue(objTarget, CloneObject(objpropertyvalue), null); 40 } 41 } 42 } 43 return objTarget; 44 } 45 } 46 }
這個方法也能夠作成一個擴展方法:對象
1 public static class ObjectExtension 2 { 3 public static object CloneObject(this object objSource) 4 { 5 //Get the type of source object and create a new instance of that type 6 Type typeSource = objSource.GetType(); 7 object objTarget = Activator.CreateInstance(typeSource); 8 9 //Get all the properties of source object type 10 PropertyInfo[] propertyInfo = typeSource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 11 12 //Assign all source property to taget object 's properties 13 foreach (PropertyInfo property in propertyInfo) 14 { 15 //Check whether property can be written to 16 if (property.CanWrite) 17 { 18 //check whether property type is value type, enum or string type 19 if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(typeof(System.String))) 20 { 21 property.SetValue(objTarget, property.GetValue(objSource, null), null); 22 } 23 //else property type is object/complex types, so need to recursively call this method until the end of the tree is reached 24 else 25 { 26 object objPropertyValue = property.GetValue(objSource, null); 27 if (objPropertyValue == null) 28 { 29 property.SetValue(objTarget, null, null); 30 } 31 else 32 { 33 property.SetValue(objTarget, objPropertyValue.CloneObject(), null); 34 } 35 } 36 } 37 } 38 return objTarget; 39 } 40 }
如今咱們調用該方法,看看結果:blog
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace ReflectionCopy 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 Employee emp = new Employee(); 13 14 emp.EmployeeId = 1000; 15 emp.EmployeeName = "IT少年"; 16 emp.Department = new Department { DepartmentId = 1, DepartmentName = "Examination" }; 17 18 Employee empclone = emp.CloneObject() as Employee; 19 20 emp.EmployeeId = 1003; 21 emp.EmployeeName = "TTT"; 22 emp.Department.DepartmentId = 3; 23 emp.Department.DepartmentName = "admin"; 24 Console.WriteLine("----emp原始對象------"); 25 Console.WriteLine("拷貝前DepartmentName應該是admin: " + emp.Department.DepartmentName); 26 Console.WriteLine("拷貝前DepartmentID應該是3: " + emp.Department.DepartmentId); 27 28 Console.WriteLine("----empclone拷貝對象------"); 29 Console.WriteLine("拷貝DepartmentName應該是Examination: " + empclone.Department.DepartmentName); 30 Console.WriteLine("拷貝DepartmentID應該是1: " + empclone.Department.DepartmentId); 31 Console.ReadKey(); 32 } 33 34 } 35 }
運行結果能夠看出和序列化和反序列化深拷貝同樣的。字符串