C#淺拷貝和深拷貝實例解析
在有些時候,我們需要從數(shù)據(jù)庫讀取數(shù)據(jù)填充對象或從硬盤讀取文件填充對象,但是這樣做相對耗時。這時候我們就想到了對象的拷貝。本文即以實例形式解析了C#淺拷貝和深拷貝的用法。具體如下:
一、淺拷貝
1.什么是"淺拷貝":
當(dāng)針對一個對象前拷貝的時候,對于對象的值類型成員,會復(fù)制其本身,對于對象的引用類型成員,僅僅復(fù)制對象引用,這個引用指向托管堆上的對象實例。
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(); //對引用類型實施淺復(fù)制
}
}
3.測試拷貝后的效果
①打印出原先對象拷貝前值類型和引用類型成員的值
②對原先對象拷貝,打印出復(fù)制對象值類型和引用類型成員的值
③改變原先對象的值,再次打印原先對象的值類型和引用類型成員的值
④再次打印復(fù)制對象值類型和引用類型成員的值
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("拷貝之前,結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema1._film._name,cinema1._room._maxSeat);
Console.WriteLine("拷貝之后,新的結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema2._film._name, cinema2._room._maxSeat);
//修改拷貝之前引用類型的字段值
cinema1._film._name = "極品飛車";
cinema1._room._maxSeat = 80;
Console.WriteLine("修改之后,結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema1._film._name, cinema1._room._maxSeat);
Console.WriteLine("修改之后,新的結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema2._film._name, cinema2._room._maxSeat);
Console.ReadKey();
}
運行結(jié)果如下:

分析:
淺拷貝關(guān)鍵點是對引用類型拷貝的是對象引用,這個引用指向托管堆上的對象實例。改變原對應(yīng)引用類型的值,會影響到復(fù)制對象。
二、深拷貝
1.什么是"深拷貝"
對引用成員指向的對象也進行復(fù)制,在托管堆上賦值原先對象實例所包含的數(shù)據(jù),再在托管堆上創(chuàng)建新的對象實例。
2.通過對每個對象成員進行復(fù)制進行深拷貝
public object Clone()
{
Room room = new Room();
room._maxSeat = this._room._maxSeat;//復(fù)制當(dāng)前引用類型成員的值到新對象
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); //復(fù)制到流中
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(); //對引用類型實施淺復(fù)制
//}
//深拷貝 對每個對象成員進行復(fù)制
public object Clone()
{
Room room = new Room();
room._maxSeat = this._room._maxSeat;//復(fù)制當(dāng)前引用類型成員的值到新對象
Film film = this._film; //值類型直接賦值
Cinema cinema = new Cinema(room, film);
return cinema;
}
//使用序列化和反序列化進行復(fù)制
public object Clone1()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this); //復(fù)制到流中
ms.Position = 0;
return (bf.Deserialize(ms));
}
}
5.測試拷貝后的效果
①打印出原先對象拷貝前值類型和引用類型成員的值
②對原先對象拷貝,打印出復(fù)制對象值類型和引用類型成員的值
③改變原先對象的值,再次打印原先對象的值類型和引用類型成員的值
④再次打印復(fù)制對象值類型和引用類型成員的值
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("拷貝之前,結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema1._film._name,cinema1._room._maxSeat);
Console.WriteLine("拷貝之后,新的結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema2._film._name, cinema2._room._maxSeat);
//修改拷貝之前引用類型的字段值
cinema1._film._name = "極品飛車";
cinema1._room._maxSeat = 80;
Console.WriteLine("修改之后,結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema1._film._name, cinema1._room._maxSeat);
Console.WriteLine("修改之后,新的結(jié)構(gòu)成員的字段值為{0},引用類型成員的字段值為{1}", cinema2._film._name, cinema2._room._maxSeat);
Console.ReadKey();
}
結(jié)果:
分析:
深拷貝后,兩個對象的引用成員已經(jīng)分離,改變原先對象引用類型成員的值并不會對復(fù)制對象的引用類型成員值造成影響。
相關(guān)文章
C#實現(xiàn)表格數(shù)據(jù)轉(zhuǎn)實體的示例代碼
在實際開發(fā)過程中,特別是接口對接之類的,對于這種需求是屢見不鮮,現(xiàn)在很多在線平臺也都提供了像json轉(zhuǎn)實體、sql轉(zhuǎn)實體等。本文將用C#實現(xiàn)這一功能,需要的可以參考一下2022-09-09
需求 : 枚舉類型在界面顯示的時候可以顯示相應(yīng)的中文信息, 這樣界面對用戶友好 . 場景?。骸≡谝恍I(yè)務(wù)中涉及到審核功能的時候, 往往有這幾個狀態(tài) :未送審 , 審核中 ,審核通過, 駁回?。∵@個時候我們會定義一個枚舉類型來描述?。?/div> 2013-03-03
C#實現(xiàn)解析百度天氣數(shù)據(jù),Rss解析百度新聞以及根據(jù)IP獲取所在城市的方法
這篇文章主要介紹了C#實現(xiàn)解析百度天氣數(shù)據(jù),Rss解析百度新聞以及根據(jù)IP獲取所在城市的方法,非常具有實用價值,需要的朋友可以參考下2014-10-10
C#實現(xiàn)Excel合并單元格數(shù)據(jù)導(dǎo)入數(shù)據(jù)集詳解
這篇文章主要為大家詳細介紹了C#如何實現(xiàn)Excel合并單元格數(shù)據(jù)導(dǎo)入數(shù)據(jù)集,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
C# 站點IP訪問頻率限制 針對單個站點的實現(xiàn)方法
下面小編就為大家?guī)硪黄狢# 站點IP訪問頻率限制 針對單個站點的實現(xiàn)方法。小編覺的挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12最新評論

