詳解 c# 克隆
克隆方法是原型設計模式中必須使用的方式,它將返回一個與當前對象數(shù)據(jù)一致的對象。正如其名,猶如一個模子雕刻而出??寺☆愋头譃閮煞N:淺克隆、深克隆。
1、淺克隆
淺克隆方式是最簡單、最直接的方式。只需要類實現(xiàn)接口ICloneable(在命名空間System.Runtime.InteropServices下)的Clone方法,在方法中使用加入對當前類的MemberwiseClone()方法即可。在淺克隆中,如果原型對象的成員變量是值類型,將復制一份給克隆對象;如果原型對象的成員變量是引用類型,則將引用對象的地址復制一份給克隆對象。

如:
public class Student:ICloneable
{
/// <summary>
/// 值類型
/// </summary>
public int ID { get; set; } /// <summary>
/// 引用類型
/// </summary>
public object obj { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
以上方法實現(xiàn)了對類對象的淺克隆方式。但是在該類中具有引用類型字段,淺克隆方法無法對引用字段進行克隆,引用字段僅僅是對其進行了地址引用。所以,當修改原本或者副本的引用字段的數(shù)據(jù)時,另一個對象的引用對象的數(shù)據(jù)同樣會變化。深克隆將有效的解決此問題。
2、深克隆
深克隆相對于淺克隆方式比較復雜。深克隆是無論原型對象的成員變量是值類型還是引用類型,都將復制一份給克隆對象,深克隆將原型對象的所有引用對象也復制一份給克隆對象。

深克隆實現(xiàn)的機制是將對象進行序列化為數(shù)據(jù)后,再次將數(shù)據(jù)反序列化為新的對象。序列化就是將對象寫到流的過程,寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在于內(nèi)存中。通過序列化實現(xiàn)的拷貝不僅可以復制對象本身,而且可以復制其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流里將其讀出來,可以實現(xiàn)深克隆。注意,在實現(xiàn)序列化前需要在類的上方標記為可序列化。本文采用的序列化方式為二進制序列化。
主要實現(xiàn)的代碼如下:
[Serializable]//標記特性:可序列化
public class Student
{
/// <summary>
/// 值類型
/// </summary>
public int ID { get; set; }
/// <summary>
/// 引用類型
/// </summary>
public object obj { get; set; }
public Student Clone( )
{
Student clone = new Student();
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
clone = formatter.Deserialize(stream) as Student;
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
}
return clone;
}
}
深克隆實現(xiàn)機制相對復雜、效率稍慢,但它克服了淺克隆方式的不足,使得克隆對象時將類中的引用類型數(shù)據(jù)完全克隆為新的對象,而不是引用原本中的對象。如此,在修改雙方的引用類型對象的數(shù)據(jù)時不會對另一方造成干擾。
但為每一個類都實現(xiàn)克隆方式,而重復書寫相同代碼未免麻煩。因此引入泛型方法。
3、泛型方法實現(xiàn)克隆
泛型的出現(xiàn)使得可以良好的解決在多個類或結(jié)構(gòu)體中都需要進行克隆時重復編寫代碼的麻煩。在外部只需要使用相關方法即可。其代碼如下:
public class Clone
{
/// <summary>
/// 深克隆
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T DepthClone<T>(T t)
{
T clone = default(T);
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(stream, t);
stream.Seek(0, SeekOrigin.Begin);
clone = (T)formatter.Deserialize(stream);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
}
return clone;
}
}
在外部使用的方法如下:
Student stu1 = new Student();//實例化一個對象 stu1.obj = new object();//實例化對象中的引用對象 Student stu2 = Clone.DepthClone(stu1);//深克隆對象
4、擴展方法
擴展方法的出現(xiàn)可以很好的解決類自身直接調(diào)用克隆方法,而不需要調(diào)用靜態(tài)類的方法,返回對象值。但其本身與泛型方法類似,不過為了使所有類都能使用定義的深克隆方法,此處使用對頂級類Object進行方法的擴展,其返回的值也是object類型。具體方法如下:
/// <summary>
/// 注:擴展方法必須在靜態(tài)類中
/// </summary>
public static class Clone
{
/// <summary>
/// 深克隆
/// </summary>
/// <param name="obj">原始版本對象</param>
/// <returns>深克隆后的對象</returns>
public static object DepthClone(this object obj)
{
object clone = new object();
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(stream, obj);
stream.Seek(0, SeekOrigin.Begin);
clone = formatter.Deserialize(stream);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
}
return clone;
}
}
使用方法示例:
Student stu1 = new Student();//實例化一個對象 stu1.obj = new object();//實例化對象中的引用對象 Student stu2 = stu1.DepthClone() as Student;//深克隆對象;注意:在此需要將object對象轉(zhuǎn)換為我們需要的對象類型
以上就是詳解 c# 克隆的詳細內(nèi)容,更多關于c# 克隆的資料請關注腳本之家其它相關文章!
相關文章
WPF利用WindowChrome實現(xiàn)自定義窗口
這篇文章主要為大家詳細介紹了WPF如何利用WindowChrome實現(xiàn)自定義窗口,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下2023-02-02
C# Fiddler插件實現(xiàn)網(wǎng)站離線瀏覽功能
本文主要介紹了C# Fiddler插件實現(xiàn)網(wǎng)站離線瀏覽功能的原理與方法。具有很好的參考價值,下面跟著小編一起來看下吧2017-02-02
C#調(diào)用sql2000存儲過程方法小結(jié)
這篇文章主要介紹了C#調(diào)用sql2000存儲過程的方法,以實例形式分別對調(diào)用帶輸入?yún)?shù)及輸出參數(shù)的存儲過程進行了詳細分析,非常具有實用價值,需要的朋友可以參考下2014-10-10

