深入解析浅复制和深复制
生活随笔
收集整理的這篇文章主要介紹了
深入解析浅复制和深复制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
通過c#類型基礎了解到變量在內存中的狀態,那么我現在想把一個變量傳遞給另一個變量,對值和對象進行復制。實際上淺度復制是把棧中的數據復制下來,深度復制是把堆上的值進行復制。
那么什么時候使用深復制什么時候來使用淺復制呢,假如我請求一次數據庫獲取到這個對象,再創建新對象的時候可能會用復制的方式來創建這個對象,而不是再去請求一次數據庫。
淺復制:
先看一段代碼,
class Program{static void Main(string[] args){int a = new int();a = 3;int b = a;a += 1;People peo = new People() { age = 19 };People peo2 = peo;peo.age = 20;Console.WriteLine("b={0},peo2={1}", b, peo2.age); //輸出b=3,peo2=20Console.Read();}}public class People{public int age;}結論:淺復制是將棧中的值復制一份,也就是值類型把這個值本身復制一份,操作原來的值對新值沒有影響。引用類型是把棧上的引用值復制一份,對象本身不復制,操作對象,新對象也會跟著變化。
深復制:
上面已經介紹了淺拷貝的實現方式,那深拷貝要如何實現呢?在前言部分已經介紹了,實現深拷貝的方式有:反射、反序列化和表達式樹。表達式樹這里還不是很清晰,持續更新吧。
// 利用反射實現深拷貝public static T CopyWithReflection<T>(T obj){Type type = obj.GetType();// 如果是字符串或值類型則直接返回if (obj is string || type.IsValueType) return obj;if (type.IsArray){Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));var array = obj as Array;Array copied = Array.CreateInstance(elementType, array.Length);for (int i = 0; i < array.Length; i++){copied.SetValue(DeepCopyWithReflection(array.GetValue(i)), i);}return (T)Convert.ChangeType(copied, obj.GetType());}object retval = Activator.CreateInstance(obj.GetType());PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic| BindingFlags.Instance | BindingFlags.Static);foreach (var property in properties){var propertyValue = property.GetValue(obj, null);if (propertyValue == null)continue;property.SetValue(retval, DeepCopyWithReflection(propertyValue), null);}return (T)retval;} //反序列化的實現方式,反序列化的方式也可以細分為3種,具體的實現如下所示:// 利用XML序列化和反序列化實現public static T CopyWithXmlSerializer<T>(T obj){object retval;using (MemoryStream ms = new MemoryStream()){XmlSerializer xml = new XmlSerializer(typeof(T));xml.Serialize(ms, obj);ms.Seek(0, SeekOrigin.Begin);retval = xml.Deserialize(ms);ms.Close();}return (T)retval;}// 利用二進制序列化和反序列實現public static T CopyWithBinarySerialize<T>(T obj){object retval;using (MemoryStream ms = new MemoryStream()){BinaryFormatter bf = new BinaryFormatter();// 序列化成流bf.Serialize(ms, obj);ms.Seek(0, SeekOrigin.Begin);// 反序列化成對象retval = bf.Deserialize(ms);ms.Close();}return (T)retval;}// 利用DataContractSerializer序列化和反序列化實現public static T DeepCopy<T>(T obj){object retval;using (MemoryStream ms = new MemoryStream()){DataContractSerializer ser = new DataContractSerializer(typeof(T));ser.WriteObject(ms, obj);ms.Seek(0, SeekOrigin.Begin);retval = ser.ReadObject(ms);ms.Close();}return (T)retval;}為了方便測試,就用反序列化的方式來進行測試:
class Program{static void Main(string[] args){People peo = new People() { age = 18 };People peo2 = (People)peo.Clone();peo.age = 20;Console.WriteLine("peo.age={0},peo2.age={1}", peo.age, peo2.age);//輸出:peo.age=20,peo2.age=18Console.Read();}}[Serializable]public class People{public int age;public object Clone(){BinaryFormatter bf = new BinaryFormatter();MemoryStream ms = new MemoryStream();bf.Serialize(ms, this);ms.Position = 0;return (bf.Deserialize(ms)); ;}}
結論就不羅嗦了復制就這么回事,主要是理解,理解變量在內存中是怎么變化的。其實js里面的深淺復制也是這么回事。
謝謝大家觀看!
總結
以上是生活随笔為你收集整理的深入解析浅复制和深复制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring Quartz cron表达
- 下一篇: Docker的简单使用