首先咱们都知道C#中有两种类型变量:那就是值类型和引用类型。
对于值类型而言,copy就相当于是全盘复制了;而对于“引用类型”而言,一般的copy只是“浅copy”,只是copy到了应用地址,这就相当于值传递了一个引用指针一样。因此对于“引用类型”实现真正的copy的时候,就需要去实现ICloneable接口中提供的Clone方法,从而去产生一个全新的对象。
一、说下什么是浅拷贝和深拷贝:
浅拷贝:只复制对象的基本类型、对象类型、仍然属于原引用,也称为“影子克隆”;
深拷贝:不止复制对象的基本类,同时也复制原对象中的对象,说完全是就是新对象产生的,也称为“深度克隆”;
二、区别:
浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中去,而对象中的引用类型的字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值它将反应在原始对象中,也就是说原始对象中对应的字段也会发生变化。
深拷贝与浅拷贝的不同是对于引用的处理,深拷贝将会在新对象中创建一个新的原始对象中对应字段相同(内容相同)的字段,也就是说这个引用和原始对象的引用是不相同的,我们在改变新对象中的这个字段的时候是不会影响到原始字段中对应字段的内容。
因此对于原型模式(property pattern)也有两种不同的处理办法,即对象的深拷贝和对象的浅拷贝。
我们可以使用MemberwiseClone方法去创建一个浅表副本(就是创建一个新对象),然后将当前对象的非静态字段复制到这个新对象里面去。如果原始对象中的字段是值类型的,则对该字段执行的是逐位复制。如果原始对象中的字段是引用类型,则对该字段只复制引用,不复制引用的对象。因此原始对象及其副本引用同一对象。深拷贝则实现了ICloneable接口,该接口可用于深拷贝和浅拷贝。
三、示例代码 Sample Code:
定义两个类:Animal.cs
public abstract class Animal
{
public int i = 1;
public double d;
public byte b;
public string[] s;
public abstract Animal Clone();
}
Dog.cs
public class Dog : Animal
{
public Dog(int i, double d, byte b, string s1, string s2)
{
this.i = i;
this.d = d;
this.b = b;
string[] ss = { s1, s2 };
this.s = ss;
}
///
/// 重写父类中的抽象方法
/// 浅拷贝、浅克隆
///
///
public override Animal Clone()
{
return (Animal)this.MemberwiseClone();
}
}
浅拷贝:
static void Main(string[] args)
{
//浅克隆、浅拷贝
Console.WriteLine("====浅克隆、浅拷贝===");
Animal a1 = new Dog(1, 2, 3, "A", "B");//实现Dog类的构造函数
Console.WriteLine("Animal a1 's members " + a1.i + "\t" + a1.b + "\t" + a1.d + a1.s[0] + a1.s[1] + "\t");
Animal a2;
a2 = a1.Clone();
Console.WriteLine("Animal a2 's members " + a2.i + "\t" + a2.b + "\t" + a2.d + a2.s[0] + a2.s[1] + "\t");
Console.WriteLine("do a1.i = 9;a1.s[0] = C ");
a1.i = 9;//改变原对象成员的值(值类型)
a1.s[0] = "C";
Console.WriteLine("Animal a1 's members " + a1.i + "\t" + a1.b + "\t" + a1.d + a1.s[0] + a1.s[1] + "\t");
Console.WriteLine("Animal a2 's members " + a2.i + "\t" + a2.b + "\t" + a2.d + a2.s[0] + a2.s[1] + "\t");
Console.WriteLine("do a2.i = 8;a2.s[1] =D ");
a2.i = 8;
a2.s[1] = "D";
Console.WriteLine("Animal a1 's members " + a1.i + "\t" + a1.b + "\t" + a1.d + a1.s[0] + a1.s[1] + "\t");
Console.WriteLine("Animal a2 's members " + a2.i + "\t" + a2.b + "\t" + a2.d + a2.s[0] + a2.s[1] + "\t");
Console.ReadKey();
}
运行结果,如下:
深拷贝:
需要对Animal.cs和Dog.cs类进行稍微的修改,因为此处需要用到二进制流:
Animal.cs
[Serializable]//表示此类可以序列化
public abstract class Animal
{
public int i = 1;
public double d;
public byte b;
public string[] s;
public abstract Animal Clone();
}
Dog.cs
[Serializable]//表示此类可以序列化
public class Dog : Animal
{
public Dog(int i, double d, byte b, string s1, string s2)
{
this.i = i;
this.d = d;
this.b = b;
string[] ss = { s1, s2 };
this.s = ss;
}
///
/// 重写父类中的抽象方法
/// 浅拷贝、浅克隆
///
///
public override Animal Clone()
{
return (Animal)this.MemberwiseClone();
}
///
/// 深拷贝、深克隆
///
///
public Dog DeppClone()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this);//将Dog对象中的成员序列化到给定的流中去:bf
ms.Seek(0, SeekOrigin.Begin);//指定到二进制流的开始位置
return (Dog)bf.Deserialize(ms);
}
}
运行代码 Sample Code:
static void Main(string[] args)
{
Console.WriteLine("====深克隆、深拷贝===");
Dog a3 = new Dog(1, 2, 3, "A", "B");
Console.WriteLine("Dog a3 's members " + a3.i + "\t" + a3.b + "\t" + a3.d + a3.s[0] + a3.s[1] + "\t");
Animal a4;
a4 = a3.DeppClone();
Console.WriteLine("Dog a4 's members " + a4.i + "\t" + a4.b + "\t" + a4.d + a4.s[0] + a4.s[1] + "\t");
Console.WriteLine("change Dog a3.i=9;a3.s[0]=C ");
a3.i = 9;
a3.s[0] = "C";
Console.WriteLine("Dog a3 's members " + a3.i + "\t" + a3.b + "\t" + a3.d + a3.s[0] + a3.s[1] + "\t");
Console.WriteLine("Dog a4 's members " + a4.i + "\t" + a4.b + "\t" + a4.d + a4.s[0] + a4.s[1] + "\t");
Console.WriteLine("change Dog a4.i=8;a4.s[0]=D ");
a4.i = 8;
a4.s[0] = "D";
Console.WriteLine("Dog a3 's members " + a3.i + "\t" + a3.b + "\t" + a3.d + a3.s[0] + a3.s[1] + "\t");
Console.WriteLine("Dog a4 's members " + a4.i + "\t" + a4.b + "\t" + a4.d + a4.s[0] + a4.s[1] + "\t");
Console.ReadKey();
}
运行结果,如图:
到这儿就结束了,希望你能Git到这个知识点哦!加油!!!!!
人不一定要生得漂亮,但却一定要活得漂亮。