再谈C#对象复制
对象复制的种类:
1.C# 不提供复制构造函数。如果您创建了新的对象并希望从现有对象复制值,您必须自行编写适当的方法。
示例
在本示例中,
2.
ICloneable接口来对对象进行克隆。当然,你也可以不去实现
ICloneable接口。
<span style="line-height: 19px; font-family:;" "="" times="" new="" roman';=""> 具体实现方法:
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;
Console.WriteLine( "**************初始化*****************");
Console.WriteLine( "cs对象的值类型:{0}", cs.Num);
Console.WriteLine( "cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine( "cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine( "-------------------------------------------------");
Console.WriteLine( "cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine( "cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine( "cs1对象的数组类型:{0}", cs1.intArr[0]);
//第二次给原始对象复制
cs.Num = 2;
cs.Str = "B";
cs.intArr[0] = 200;
//现在我们看看cs和cs1两个对象的值
Console.WriteLine( "**************先将cs值改变后变化如下*****************");
Console.WriteLine( "cs对象的值类型:{0}", cs.Num);
Console.WriteLine( "cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine( "cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine( "-------------------------------------------------" );
Console.WriteLine( "cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine( "cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine( "cs1对象的数组类型:{0}", cs1.intArr[0]);
//现在我们给副本对象进行赋值看看原始对象的值
cs1.Num = 3;
cs1.Str = "C";
cs1.intArr[0] = 300;
Console.WriteLine( "**************先将cs1值改变后变化如下*****************");
Console.WriteLine( "cs对象的值类型:{0}", cs.Num);
Console.WriteLine( "cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine( "cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine( "-------------------------------------------------");
Console.WriteLine( "cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine( "cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine( "cs1对象的数组类型:{0}", cs1.intArr[0]);
Console.WriteLine( "Output Complete!Press Any Key To Continue.");
Console.ReadKey();
}
}
}
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;
Console.WriteLine( "**************初始化*****************");
Console.WriteLine( "cs对象的值类型:{0}", cs.Num);
Console.WriteLine( "cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine( "cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine( "-------------------------------------------------");
Console.WriteLine( "cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine( "cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine( "cs1对象的数组类型:{0}", cs1.intArr[0]);
//第二次给原始对象复制
cs.Num = 2;
cs.Str = "B";
cs.intArr[0] = 200;
//现在我们看看cs和cs1两个对象的值
Console.WriteLine( "**************先将cs值改变后变化如下*****************");
Console.WriteLine( "cs对象的值类型:{0}", cs.Num);
Console.WriteLine( "cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine( "cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine( "-------------------------------------------------" );
Console.WriteLine( "cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine( "cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine( "cs1对象的数组类型:{0}", cs1.intArr[0]);
//现在我们给副本对象进行赋值看看原始对象的值
cs1.Num = 3;
cs1.Str = "C";
cs1.intArr[0] = 300;
Console.WriteLine( "**************先将cs1值改变后变化如下*****************");
Console.WriteLine( "cs对象的值类型:{0}", cs.Num);
Console.WriteLine( "cs对象的string引用类型:{0}", cs.Str);
Console.WriteLine( "cs对象的数组类型:{0}", cs.intArr[0]);
Console.WriteLine( "-------------------------------------------------");
Console.WriteLine( "cs1对象的值类型:{0}", cs1.Num);
Console.WriteLine( "cs1对象的string引用类型:{0}", cs1.Str);
Console.WriteLine( "cs1对象的数组类型:{0}", cs1.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
从结果看出,内存深层复制完全对原始对象进行了复制。