对C#对象的Shallow、Deep Cloning认识
好像园内比较多博客对 Shallow、Deep Cloning的翻译是深拷贝、浅拷贝,当时我懵了,这个叫法怎么怪怪的。
就好像看军情观察室,台湾评论员,导弹叫飞弹。
至于它们的区别,一张图就可以解释。
这两个概念,经常对一些对象操作时,忘了自己使用的是shallow 还是deep,而搞到神经大条。
MSDN的解释是:
Clone can be implemented either as a deep copy or a shallow copy.In a deep copy, all objects are duplicated; whereas, in a shallow copy, only the top-level objects are duplicated and the lower levels contain references.http://msdn.microsoft.com/zh-cn/library/system.icloneable.clone.aspx
Shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object.If a field is a value type, a bit-by-bit copy of the field is performed.If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.http://msdn.microsoft.com/zh-cn/library/system.object.memberwiseclone.aspx
先说一下string,因为测试代码用了string对象:
string testClone = "a测试"; testClone = "b测试"; Console.WriteLine("testClone:" + testClone);
.entrypoint // 代码大小 37 (0x25) .maxstack 2 .locals init ([0] string testClone) IL_0000: nop IL_0001: ldstr bytearray (61 00 4B 6D D5 8B ) // a.Km.. IL_0006: stloc.0 IL_0007: ldstr bytearray (62 00 4B 6D D5 8B ) // b.Km.. IL_000c: stloc.0 IL_000d: ldstr bytearray (74 00 65 00 73 00 74 00 43 00 6C 00 6F 00 6E 00 // t.e.s.t.C.l.o.n. 65 00 1A FF ) // e... IL_0012: ldloc.0 IL_0013: call string [mscorlib]System.String::Concat(string, string) IL_0018: call void [mscorlib]System.Console::WriteLine(string) IL_001d: nop IL_001e: call int32 [mscorlib]System.Console::Read() IL_0023: pop IL_0024: ret
testClone = "b测试";创建了"b测试"对象,并将该对象指引赋值给 testClone;
String 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。看来似乎修改了 String 对象的方法实际上是返回一个包含修改内容的新 String 对象。如果需要修改字符串对象的实际内容,请使用 System.Text.StringBuilder 类。
想查看IL指令,请看中英文对照表:
CN-http://www.cnblogs.com/flyingbirds123/archive/2011/01/29/1947626.html;
ES-http://en.csharp-online.net/CIL_Instruction_Set.
下面是我的测试代码:
CouponConfig couponClone = new CouponConfig() { Amount = 10, CouponName = "测试1", ListTest = new List<string> { "a", "b" } }; CouponConfig coupon1Clone = couponClone; CouponConfig coupon2Clone = (CouponConfig)couponClone.Clone(); CouponConfig coupon3Clone = null; using (Stream objectStream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(objectStream, couponClone); objectStream.Seek(0, SeekOrigin.Begin); coupon3Clone = (CouponConfig)formatter.Deserialize(objectStream); } couponClone.CouponName = "测试2"; coupon2Clone.ListTest.Add("c"); coupon3Clone.ListTest.Add("d"); Console.WriteLine("couponClone:" + couponClone.CouponName); Console.WriteLine("coupon2Clone:" + coupon2Clone.CouponName); foreach (string c in couponClone.ListTest) { Console.Write(c); } Console.WriteLine(""); foreach (string c in coupon2Clone.ListTest) { Console.Write(c); } Console.WriteLine(""); foreach (string c in coupon3Clone.ListTest) { Console.Write(c); } Console.WriteLine(""); Console.Read();
[Serializable] public class CouponConfig : ICloneable { private CouponConfig config; public CouponConfig Config { get { if (config == null) { config = null; } return config; } } public CouponConfig() { } #region Model private int _amount; private string _couponname; private List<string> listTest; public string CouponName { get { return _couponname; } set { _couponname = value; } } public List<string> ListTest { get { return listTest; } set { listTest = value; } } public int Amount { set { _amount = value; } get { return _amount; } } #endregion Model public object Clone() { return this.MemberwiseClone(); } }
运行结果是:
接下来思考一下吧,datatable的Copy、Clone是什么cloning呢?
DataTable dt = new DataTable(); DataTable dtcopy = dt.Copy(); DataTable dtclone = dt.Clone();
当然最常见的是Ling to sql 的操作,where、OrderBy···,是什么cloning呢?
对象类实现了ICloneable就可以使用this.MemberwiseClone(); 实现shallow cloning;
也可以自己写clone
public class Person : ICloneable { public string Name; public Person Spouse; public object Clone() { Person p = new Person(); p.Name = this.Name; if (this.Spouse != null) p.Spouse = (Person)this.Spouse.Clone(); return p; } }
Deep Cloning可以使用 Serialization
using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary;
public static class ObjectCopier { /// <summary> /// Perform a deep Copy of the object. /// </summary> /// <typeparam name="T">The type of object being copied.</typeparam> /// <param name="source">The object instance to copy.</param> /// <returns>The copied object.</returns> public static T Clone<T>(T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("The type must be serializable.", "source"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } IFormatter formatter = new BinaryFormatter(); Stream stream = new MemoryStream(); using (stream) { formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(stream); } } }
原文链接:http://www.cnblogs.com/daihuiquan/archive/2013/02/14/2910657.html