C#中的淺拷貝與深拷貝

来源:https://www.cnblogs.com/wml-it/archive/2023/08/30/17667229.html
-Advertisement-
Play Games

## 前言 眾所周知,C#中有兩種類型變數:那就是**值類型**和**引用類型**。對於值類型而言,copy就相當於是全盤複製了,真正的實現了複製,屬於**深拷貝**;而對於引用類型而言,一般的copy只是**淺拷貝**,只是copy到了引用對象的地址,相當於值傳遞了一個引用指針,==新的對象通過地 ...


前言

眾所周知,C#中有兩種類型變數:那就是值類型引用類型。對於值類型而言,copy就相當於是全盤複製了,真正的實現了複製,屬於深拷貝;而對於引用類型而言,一般的copy只是淺拷貝,只是copy到了引用對象的地址,相當於值傳遞了一個引用指針,新的對象通過地址引用仍然指向原有記憶體中的對象。因此對引用類型實現深拷貝的時候,就需要去實現ICloneable介面中提供的Clone方法,從而去產生一個全新的對象。

什麼是淺拷貝和深拷貝

淺拷貝:只複製對象的基本類型、對象類型、仍然屬於原引用,也稱為影子克隆

image

深拷貝:不止複製對象的基本類,同時也複製原對象中的對象,完全就是新對象產生的,也稱為深度克隆

image

淺拷貝的實現

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

建群聲明: 本著技術在於分享,方便大家交流學習的初心,特此建立【編程內功修煉交流群】,為大家答疑解惑。熱烈歡迎各位愛交流學習的程式員進群,也希望進群的大佬能不吝分享自己遇到的技術問題和學習心得!進群方式:掃碼關註公眾號,後臺回覆【進群】。



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # Core 建造者模式又稱為`生成器模式`,主要用於對複雜對象的構建、初始化,它可以將多個簡單的組件對象按順序一步步組裝起來,最終構建成一個複雜的成品對象。 與工廠系列模式不同的是,建造者模式的主要目的在於把煩瑣的**構建過程**從不同對象中抽離出來,使其脫離並獨立於產品類與工廠類,最終實現**用 ...
  • 本文是區塊鏈瀏覽器系列的第五篇,項目完整代碼在[這裡](https://github.com/mengbin92/browser/tree/main)。 在[上一篇文章](https://mengbin.top/2023-08-20-browser2/)中給瀏覽器增加了簡單的用戶認證,至此瀏覽器的基 ...
  • # Background knowledge 在Java中,Cloneable 介面是一個標記介面(Marker Interface,它們內部都沒有方法和屬性),實現Cloneable介面表示該對象能被克隆,能使用Object.clone()方法。 要實現克隆功能,需要滿足以下兩個條件: - 類實現 ...
  • # 第二章——python基礎語法1: ## 1、輸入和輸出 ### a、使用print()進行列印(輸出)。 ``` print('hello,python') print('hello,world',end='') ``` - pritnt)(輸出內容後,預設會換行。要使其不換行,**則使用pr ...
  • `Matplotlib` 庫是一個用於數據可視化和繪圖的 Python 庫。它提供了大量的函數和類,可以幫助用戶輕鬆地創建各種類型的圖表,包括直方圖、箱形圖、散點圖、餅圖、條形圖和密度圖等。 使用 `Matplotlib` 的過程中,遇到的難點並不在於繪製各類的圖形,因為每種圖形都有其對應的API。 ...
  • 本文在瞭解netty核心組件的前提下,進一步瞭解組件如何在整個伺服器啟動過程如何被創建,如何組件之間配合來使用。首先也是先瞭解下大概服務端的啟動過程,並且在瞭解過程中我們帶著自己的問題去在學習過程中探尋答案 ...
  • 最近做了個脫敏的需求,要對系統中的敏感信息,如手機號、車牌號、身份證號、銀行卡號等進行脫敏顯示。 效果類似下麵這樣: ![](https://images.zwwhnly.com/picture/2023/image-20230829095822435.png) 簡單來說,就是對敏感信息中的某幾位進 ...
  • ### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 本篇是《java與es8實戰》系列的第五 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...