## 前言 眾所周知,C#中有兩種類型變數:那就是**值類型**和**引用類型**。對於值類型而言,copy就相當於是全盤複製了,真正的實現了複製,屬於**深拷貝**;而對於引用類型而言,一般的copy只是**淺拷貝**,只是copy到了引用對象的地址,相當於值傳遞了一個引用指針,==新的對象通過地 ...
前言
眾所周知,C#中有兩種類型變數:那就是值類型和引用類型。對於值類型而言,copy就相當於是全盤複製了,真正的實現了複製,屬於深拷貝;而對於引用類型而言,一般的copy只是淺拷貝,只是copy到了引用對象的地址,相當於值傳遞了一個引用指針,新的對象通過地址引用仍然指向原有記憶體中的對象。因此對引用類型實現深拷貝的時候,就需要去實現ICloneable介面中提供的Clone方法,從而去產生一個全新的對象。
什麼是淺拷貝和深拷貝
淺拷貝:只複製對象的基本類型、對象類型、仍然屬於原引用,也稱為影子克隆;
深拷貝:不止複製對象的基本類,同時也複製原對象中的對象,完全就是新對象產生的,也稱為深度克隆;
淺拷貝的實現
C#中System.Object
是所有類類型、結構類型、枚舉類型和委托類型的基類。可以說它是類型繼承的基礎。System.Object
包括一個用於創建當前對象實例的一份拷貝的MemberwiseClone
的成員方法。MemberwiseClone
方法創建一個新對象的淺拷貝,並把當前對象實例的非靜態欄位拷貝至新對象實例中。通過屬性,對象拷貝能夠正確執行:如果屬性是值類型,那麼將按位拷貝數據,如果屬性是引用類型,那麼將拷貝原始對象的引用,也就是說,克隆對象指向同一個對象實例。這就意味著MemberwiseClone
方法並未創建一個對象的深拷貝。
Object成員方法MemberwiseClone實現:
/// <summary>
/// Student 學生類
/// </summary>
public class Student
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 教室
/// </summary>
public ClassRoom Room { get; set; }
/// <summary>
/// 淺拷貝克隆方法
/// </summary>
/// <returns></returns>
public Student Clone()
{
return (Student)this.MemberwiseClone();
}
}
/// <summary>
/// 班級類
/// </summary>
public class ClassRoom
{
/// <summary>
/// 班級Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 班級名稱
/// </summary>
public string Name { get; set; }
}
深拷貝的實現
深拷貝是指複製對象的所有數據,包括對象內部引用的其他對象。這意味著,新的對象和原始對象不共用任何數據,它們是完全獨立的。可通過提供如下四種方法實現:
利用反射實現:
public static T DeepCopy<T>(T obj)
{
//如果是字元串或值類型則直接返回
if (obj is string || obj.GetType().IsValueType) return obj;
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, DeepCopy(field.GetValue(obj))); }
catch { }
}
return (T)retval;
}
利用xml序列化和反序列化實現:
public T DeepCopy<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 DeepCopy<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;
淺拷貝與深拷貝的區別
淺拷貝:是指將對象中的數值類型的欄位拷貝到新的對象中,而對象中的引用類型的欄位則指複製它的一個引用到目標對象。如果改變目標對象中引用型欄位的值它將反應在原始對象中,也就是說原始對象中對應的欄位也會發生變化。
深拷貝:與淺拷貝的不同是對於引用的處理,深拷貝將會在記憶體中創建一個新的對象,對應欄位和原始對象完全相同。也就是說這個引用和原始對象的引用是不相同的,因為新對象與原對象引用地址不同,我們在改變新對象中的這個欄位的時候是不會影響到原始欄位中對應欄位的內容。
本文來自博客園,作者:碼農阿亮,轉載請註明原文鏈接:https://www.cnblogs.com/wml-it/p/17667229.html
技術的發展日新月異,隨著時間推移,無法保證本博客所有內容的正確性。如有誤導,請大家見諒,歡迎評論區指正!
開源庫地址,歡迎點亮:
GitHub:https://github.com/ITMingliang
Gitee: https://gitee.com/mingliang_it
GitLab: https://gitlab.com/ITMingliang
建群聲明: 本著技術在於分享,方便大家交流學習的初心,特此建立【編程內功修煉交流群】,為大家答疑解惑。熱烈歡迎各位愛交流學習的程式員進群,也希望進群的大佬能不吝分享自己遇到的技術問題和學習心得!進群方式:掃碼關註公眾號,後臺回覆【進群】。