拷贝对象的三种方式

对象拷贝又叫对象克隆或对象复制,要求在不影响原对象及其内容的情况下,产生该对象的一个副本并顺利工作。对象克隆一般用于把对象初始化为默认状态。根据这几天的观察,共总结出三种对象拷贝的方法,下面分别介绍。
在介绍之前,首先要分清浅拷贝和深拷贝之间的区别。所谓浅拷贝,是指拷贝了对象整体的引用或者对象内部某些引用类型的引用,而非引用类型的属性则拷贝其值。这么说有些抽象,举个例子,假如对象objA(A类的一个实例)有一个属性是objB(B类的一个实例,是引用类型),如果浅拷贝objA到另外一个A类的实例,那么只是拷贝了objB的引用,而没有拷贝其值(当然值也一样),其他的非引用类型的属性,则直接拷贝值。浅拷贝拷贝的“量”感觉较少,因为只是拷贝了引用类型的引用而没有拷贝其值,这样反而让两对象之间的联系更加紧密,只要有一个对象的某个引用类型的属性变化,都会使另外一个对象发生同样的变化,但值类型的却不会这样,因为它只是拷贝了值。当然,如果你为了图省事,直接把objA以赋值的形式赋给了另外一个对象,那么本身就是拷贝了这个对象的引用(对象是引用类型),对象内所有属性,无论是引用类型还是值类型,只要有一个对象发生变化,另外一个对象都会发生变化,因为两个对象指向了同一地址,所以内部属性当然也指向了统一地址。与浅拷贝不同,深拷贝只是拷贝了objA的属性的值,即使属性属于引用类型,也不会拷贝引用,只是拷贝它的值!于是,两个对象没有任何关系,改动其中一个,不会对另外一个产生影响。
第一种方法:对象间的直接赋值
用“=”给两个对象赋值,这是我们经常用到的,但这不是一种好习惯,因为这样属于绝对的浅拷贝,两个对象指向同一地址,共同变化。
Eg,假如有一个Teacher类,然后
Teacher teaTest1 = new Teacher();
Teacher teaTest2 = teaTest1;//直接赋值
这样完成的直接赋值,teaTest1和teaTest2实际上是同一个对象,两对象指向同一地址,只要其中任何一个对象变化,都会引起另外一个的变化,无论什么属性。所以,这是一种绝对的浅拷贝方式。
第二种方法:对象属性间的赋值
第一种方法是用“=”给对象赋值,这次是用“=”给对象的属性赋值,这就存在这样一种问题,如果该属性是引用类型的,则其中一个对象该属性变化,一定会影响到另外一个对象的该属性,即两属性指向同一地址;如果该属性是值类型,则只是拷贝了该属性的值,其中一个对象该属性的变化,不再影响到另外一个对象该属性的值。
通常这种对属性的赋值,是在类的构造函数内实现的。Eg,部分属性的赋值,则用直接赋值,若所有属性都赋值,则可以使用反射机制来实现。
using System;
using System.Reflection;
namespace利用反射拷贝对象
{
public enum InitializeMethods{PartInitialize,AllInitialize};//拷贝对象属性的全部还是部分
public class Teacher
{ private int intGrade;
private int intSalary;
private string strDept = string.Empty;
public int Grade{get{return this.intGrade;}set{this.intGrade = value;}}
public int Salary{get{return this.intSalary;}set{this.intSalary = value;}}
public string Dept{get{return this.strDept;}set{this.strDept = value;}}
public Teacher()//构造函数1
{
}
public Teacher(int grade,int salary,string dept)//构造函数2
{
this.intGrade = grade;
this.intSalary = salary;
this.strDept = dept;
}
public Teacher(Teacher teach,InitializeMethods initM)//构造函数3
{
if(initM == InitializeMethods.PartInitialize)//根据要求选择要拷贝的对象属性,这里选择了两个属性
{
this.intGrade = teach.intGrade;
this.intSalary = teach.intSalary;
}
else
if(initM == InitializeMethods.AllInitialize)//利用反射机制获得对象teach的所有属性信息并拷贝到另一个对象
{
System.Reflection.PropertyInfo[] pInfoArray = teach.GetType().GetProperties();
foreach(PropertyInfo pInfoTmp in pInfoArray)
{
object objMyValue = teach.GetType().InvokeMember(pInfoTmp.Name,BindingFlags.GetProperty,null,teach,null);
teach.GetType().InvokeMember(pInfoTmp.Name,BindingFlags.SetProperty,null,this,new object[]{objMyValue});
}
}
}
}
}
第三种方法:使用ICloneable接口进行深拷贝
Eg
using System;
namespace ICloneable接口的用途
{
public class Women:ICloneable
{
public Women()
{
}
public Women(string strN,int intA,Men menM)
{
this.strName = strN;
this.intAge = intA;
this.menMale = menM;
}
private string strName;
private int intAge;
private Men menMale;
public string Name
{
set
{this.strName = value; }
get
{return this.strName; }
}
public int Age
{set
{this.intAge = value; }
get
{return this.intAge; }
}
public Men Male
{
set
{this.menMale = value; }
get
{return this.menMale; }
}
#region ICloneable 成员
public object Clone()
{return new Women(this.strName,this.intAge,this.menMale) as Women; }
// public object Clone()//这个属于浅拷贝
// {
// return this.MemberwiseClone();
// }
#endregion
}
}
使用时,Women womenTest 2= womenTest1.Clone();
或者通过接口进行调用,更加有利于程序的整合。eg
ICloneable pC = womenTest1;
Women womenTest2 = pC.Clone();
阅读更多
上一篇AO中的对高亮显示的局部刷新及对局部刷新方法的总结
下一篇非托管资源的回收问题
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭