在.net framework中,提供了ICloneable接口來對對象進行克隆。當然,你也可以不去實現ICloneable接口而直接自己定義一個Clone()方法,當然,還是推薦實現ICloneable接口。
具體實現方法
using UnityEngine; using System.Collections; using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; [Serializable] public class Job { public int id; public string JobName { get; set; } public override string ToString() { return this.JobName; } public int ID { get { return id;} set { id = value;} } } [Serializable] public class Person:ICloneable { public int Age { get; set; } //值類型字段 public string Name { get; set; } //字符串 public Job Job { get; set; } //引用類型字段 //深拷貝 public Person DeepClone() { using (Stream objectStream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(objectStream,this); objectStream.Seek(0, SeekOrigin.Begin); return formatter.Deserialize(objectStream) as Person; } } public object Clone() { return this.MemberwiseClone(); //淺拷貝 } //淺拷貝 public Person ShallowClone() { return this.Clone() as Person; } }
測試案例:
using UnityEngine; using System.Collections; //測試C# 類拷貝 public class ClassCloneTest : MonoBehaviour { // Use this for initialization void Start () { Person p = new Person() { Name = "test0001", Age = 20,Job = new Job(){JobName="Coder",ID = 100022 } }; string Str = ""; Str = string.Format("修改前:p.Name={0},p.Age={1},p.Job.JobName={2}", p.Name, p.Age, p.Job.JobName); Person p1 = p.ShallowClone(); Person p2 = p.DeepClone(); Debug.Log(Str); Str = string.Format("修改前:p1.Name={0},p1.Age={1},p1.Job.JobName={2}", p1.Name, p1.Age, p1.Job.JobName); Debug.Log(Str); Str = string.Format("修改前:p2.Name={0},p2.Age={1},p2.Job.JobName={2}", p2.Name, p2.Age, p2.Job.JobName); Debug.Log(Str); //修改p的所有字段值 Debug.Log("修改P1的值: "); p1.Name = "test000222222"; p1.Age = 100; p1.Job.JobName = "Manager"; p1.Job.ID = 1111; Str = string.Format("修改后:p.Name={0},p.Age={1},p.Job.JobName={2}", p.Name, p.Age, p.Job.JobName); Debug.Log(Str); Str = string.Format("修改后:p1.Name={0},p1.Age={1},p1.Job.JobName={2}", p1.Name, p1.Age, p1.Job.JobName); Debug.Log(Str); Str = string.Format("修改后:p2.Name={0},p2.Age={1},p2.Job.JobName={2}", p2.Name, p2.Age, p2.Job.JobName); Debug.Log(Str); } }
結果輸出:
結論:
這個結果可以看出,淺表副本和原始副本並不是一個對象,但是,淺表副本復制了原始對象的值類型和string類型,但是數組只復制了引用。
這個現象很有趣,按照MSDN的定義:“MemberwiseClone 方法創建一個淺表副本,方法是創建一個新對象,然后將當前對象的非靜態字段復制到該新對象。
如果字段是值類型的,則對該字段執行逐位復制。如果字段是引用類型,則復制引用但不復制引用的對象;因此,原始對象及其復本引用同一對象。”,
但是,在實際上,string應該也是引用類型,但是,淺表副本卻復制了這個值。
無論是淺拷貝與深拷貝,C#都將源對象中的所有字段復制到新的對象中。不過,對於值類型字段,引用類型字段以及字符串類型字段的處理,兩種拷貝方式存在一定的區別(見下表)。
參考: http://visionsky.blog.51cto.com/blog/733317/237917
http://blog.csdn.net/yl2isoft/article/details/12200513