C#淺拷貝和深拷貝實例解析
在有些時候,我們需要從數(shù)據(jù)庫讀取數(shù)據(jù)填充對象或從硬盤讀取文件填充對象,但是這樣做相對耗時。這時候我們就想到了對象的拷貝。本文即以實例形式解析了C#淺拷貝和深拷貝的用法。具體如下:
一、淺拷貝
1.什么是"淺拷貝":
當針對一個對象前拷貝的時候,對于對象的值類型成員,會復(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ù)制當前引用類型成員的值到新對象
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ù)制當前引用類型成員的值到新對象
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#使用Excel動態(tài)函數(shù)實現(xiàn)生成依賴列表
這篇文章主要為大家詳細介紹了如何在C#中使用?Excel?動態(tài)函數(shù)生成依賴列表,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2024-02-02
C#實現(xiàn)應(yīng)用程序的監(jiān)控與調(diào)試的示例代碼
日志記錄是軟件開發(fā)中不可或缺的功能,它能幫助開發(fā)者在應(yīng)用程序運行時記錄重要信息,本文就來介紹一下常用日志記錄功能以及常用的日志庫,感興趣的可以了解一下2024-03-03

