对象复制探讨
对象复制的种类:1.构造复制函数;2.克隆方法;
1. 构造复制函数(以下摘抄自MSDNhttp://msdn.microsoft.com/zh-cn/library/ms173116(VS.80).aspx)
与有些语言不同,C# 不提供复制构造函数。如果您创建了新的对象并希望从现有对象复制值,您必须自行编写适当的方法。
示例
在本示例中,Person类包含一个构造函数,该构造函数接受另一个 Person 类型的对象作为参数。然后此对象的字段中的内容将分配给新对象中的字段。
class Person
{
private string name;
private int age;
// Copy constructor.
public Person(Person previousPerson)
{
name = previousPerson.name;
age = previousPerson.age;
}
// Instance constructor.
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
// Get accessor.
public string Details
{
get
{
return name + " is " + age.ToString();
}
}
}
class TestPerson
{
static void Main()
{
// Create a new person object.
Person person1 = new Person("George", 40);
// Create another new object, copying person1.
Person person2 = new Person(person1);
System.Console.WriteLine(person2.Details);
}
}
这种方法有个很明显的的缺点就是必须在构造函数类对类的字段和属性进行赋值。如果类的字段很多,会是一个噩梦。
2. 克隆方法
在.net framework中,提供了ICloneable接口来对对象进行克隆。当然,你也可以不去实现ICloneable接口而直接自己定义一个Clone()方法,当然,还是推荐实现ICloneable接口。
具体实现方法:
使用方法返回
{
1.return this as object;
2.return this.MemberwiseClone() as object;
3.return new CloneClass() as object
4.{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream) as CloneClass;
}
}
实例代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace CloneSample
{
[Serializable]
class CloneClass:ICloneable
{
int num; //值类型
public int Num //封装值字段
{
get { return num; }
set { num = value; }
}
string str; //string引用类型
public string Str //封装引用字段
{
get { return str; }
set { str = value; }
}
//数组引用类型
public int[] intArr=new int[2];
//实现接口的方法
public Object Clone()
{
//return this; //返回同一个对象的引用
//return this.MemberwiseClone(); //返回一个浅表副本
//return new CloneClass(); //返回一个深层副本
{ //返回一个内存副本
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream);
}
}
}
//执行类
class ProgramRun
{
public static void Main()
{
CloneClass cs = new CloneClass();
//第一次给对象赋值
cs.Num = 1;
cs.Str = "A";
cs.intArr[0] = 100;
CloneClass cs1 = cs.Clone() as CloneClass;
//第二次给原始对象复制
cs.Num = 2;
cs.Str = "B";
cs.intArr[0] = 200;
//现在我们看看cs和cs1两个对象的值
Console.WriteLine("cs对象的值类型:{0}",cs.Num);
Console.WriteLine("cs对象的string引用类型:{0}",cs.Str);
Console.WriteLine("cs对象的数组类型:{0}",cs.intArr[0]);
Console.WriteLine("cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine("cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine("cs对象的数组类型:{0}", cs1.intArr[0]);
//现在我们给副本对象进行赋值看看原始对象的值
cs1.Num = 3;
cs1.Str = "C";
cs1.intArr[0] = 300;
Console.WriteLine("cs对象的值类型:{0}", cs.Num);
Console.WriteLine("cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine("cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine("Output Complete!Press Any Key To Continue.");
Console.ReadKey();
}
}
}
输出结果分析:
1. 返回同一个对象的引用的结果:
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:200
cs1对象的值类型:2
cs1对象的string引用类型:B
cs对象的数组类型:200
cs对象的值类型:3
cs对象的string引用类型:C
cs对象的数组类型:300
可以看到,cs和cs1完全是同一个对象,cs修改,cs1的值也跟着改变;cs1修改,cs也跟着改变。
2.返回一个浅表副本的结果:
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:200
cs1对象的值类型:1
cs1对象的string引用类型:A
cs对象的数组类型:200
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:300
这个结果可以看出,浅表副本和原始副本并不是一个对象,但是,浅表副本复制了原始对象的值类型和string类型,但是数组只复制了引用。这个现象很有趣,按照MSDN的定义:“MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。”,但是,在实际上,string应该也是引用类型,但是,浅表副本却复制了这个值。
3 返回一个深层副本的结果
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:200
cs1对象的值类型:0
cs1对象的string引用类型:
cs对象的数组类型:0
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:200
从结果可以看到,深层副本完全复制了对象的结构。
4.返回一个内存副本的结果
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:200
cs1对象的值类型:1
cs1对象的string引用类型:A
cs对象的数组类型:100
cs对象的值类型:2
cs对象的string引用类型:B
cs对象的数组类型:200
从结果看出,内存深层复制完全对原始对象进行了复制。