C#淺拷貝和深拷貝實例解析

高洛峰
發布: 2017-01-19 11:41:50
原創
1596 人瀏覽過

在有些時候,我們需要從資料庫讀取資料填充對像或從硬碟讀取文件填充對象,但是這樣做相對耗時。這時候我們就想到了物件的拷貝。本文即以實例形式解析了C#淺拷貝和深拷貝的用法。具體如下:

一、淺拷貝

1.什麼是"淺拷貝":

當針對一個對象前拷貝的時候,對於對象的值類型成員,會複製其本身,對於對象的引用類型成員,僅僅複製物件引用,這個引用指向託管堆上的物件實例。

2.有一個對象,包含引用類型的類別成員和值類型的struct成員

Cinema包含引用類型成員Room和值類型成員Film。

public class Room
{
  public int _maxSeat;
 
  public Room(int maxSeat)
  {
    this._maxSeat = maxSeat;
  }
}
 
public struct Film
{
  public string _name;
 
  public Film(string name)
  {
    this._name = name;
  }
}
 
public class Cinema
{
  public Room _room;
  public Film _film;
 
  public Cinema(Room room, Film film)
  {
    this._room = room;
    this._film = film;
  }
 
  public object Clone()
  {
    return MemberwiseClone(); //对引用类型实施浅复制
  }
}
登入後複製

3.測試拷貝後的效果

①列印出原先物件拷貝前值類型與引用型成員的值 
②對原先物件拷貝改變原先物件的值,再次列印原先物件的值類型和引用型別成員的值 
④再次列印複製物件值型別與參考型別成員的值

static void Main(string[] args)
{
  Room room1 = new Room(60);
  Film film1 = new Film("家园防线");
  Cinema cinema1 = new Cinema(room1, film1);
  Cinema cinema2 = (Cinema)cinema1.Clone();
  Console.WriteLine("拷贝之前,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name,cinema1._room._maxSeat);
 
  Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
 
  //修改拷贝之前引用类型的字段值
  cinema1._film._name = "极品飞车";
  cinema1._room._maxSeat = 80;
 
  Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
  Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
 
  Console.ReadKey();
}
登入後複製

分析:

拷貝關鍵點是對淺數位引用拷貝的是物件引用,這個引用指向託管堆上的物件實例。改變原對應引用類型的值,會影響複製物件。

二、深拷貝

1.什麼是"深拷貝"

對引用成員指向的對像也進行複製,在託管堆上賦值原先對象實例所包含的數據,再在託管堆上創建新的對象實例。

2.透過對每個物件成員進行複製進行深拷貝

public object Clone()
{
  Room room = new Room();
  room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象
  Film film = this._film; //值类型直接赋值
  Cinema cinema = new Cinema(room, film);
  return cinema;
}
登入後複製

3.也可以透過序列化和反序列化進行深拷貝

public object Clone1()
{
  BinaryFormatter bf = new BinaryFormatter();
  MemoryStream ms = new MemoryStream();
  bf.Serialize(ms, this); //复制到流中
  ms.Position = 0;
  return (bf.Deserialize(ms));
}
登入後複製

4.採用序列化和反序列化深拷貝,但必須將所有的類別打上[Serializable],測試程式碼如下:

[Serializable]
public class Room
{
  public int _maxSeat;
 
  public Room()
  {}
 
  public Room(int maxSeat)
  {
    this._maxSeat = maxSeat;
  }
}
 
[Serializable]
public struct Film
{
  public string _name;
 
  public Film(string name)
  {
    this._name = name;
  }
}
 
[Serializable]
public class Cinema
{
  public Room _room;
  public Film _film;
 
  public Cinema(Room room, Film film)
  {
    this._room = room;
    this._film = film;
  }
 
  //浅拷贝
  //public object Clone()
  //{
  //  return MemberwiseClone(); //对引用类型实施浅复制
  //}
 
  //深拷贝 对每个对象成员进行复制
  public object Clone()
  {
    Room room = new Room();
    room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象
    Film film = this._film; //值类型直接赋值
    Cinema cinema = new Cinema(room, film);
    return cinema;
  }
 
  //使用序列化和反序列化进行复制
  public object Clone1()
  {
    BinaryFormatter bf = new BinaryFormatter();
    MemoryStream ms = new MemoryStream();
    bf.Serialize(ms, this); //复制到流中
    ms.Position = 0;
    return (bf.Deserialize(ms));
  }
}
登入後複製

   

5.測試拷貝後的效果

①列印出原先物件對原先物件類型成員的值拷貝,列印出複製物件值型別和引用型別成員的值 

③改變原先物件的值,再列印原先物件的值型別和引用型別成員的值 
④再次列印複製物件值型別及引用型別成員的值

static void Main(string[] args)
   {
     Room room1 = new Room(60);
     Film film1 = new Film("家园防线");
     Cinema cinema1 = new Cinema(room1, film1);
     Cinema cinema2 = (Cinema)cinema1.Clone1();
     Console.WriteLine("拷贝之前,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name,cinema1._room._maxSeat);
 
     Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
 
     //修改拷贝之前引用类型的字段值
     cinema1._film._name = "极品飞车";
     cinema1._room._maxSeat = 80;
 
     Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
     Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
 
     Console.ReadKey();
   }
登入後複製

   

結果:

C#淺拷貝和深拷貝實例解析分析:

深拷貝後,兩個對象的引用成員已經分離,改變原先對象引用類型成員的值

深拷貝後,兩個對象的引用成員已經分離,改變原先對象引用類型成員的值並不值影響。

更多C#淺拷貝和深拷貝實例解析相關文章請關注PHP中文網!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!