C#List的深复制(转)
1、关于深拷贝和浅拷贝
C#⽀持两种类型:值类型和引⽤类型
值类型(Value Type):如 char, int, float,枚举类型和结构类型
引⽤类型(Reference Type):如Class类型、接⼝类型、委托类型、数组类型。
如何来划分它们?
以它们在计算机内存中如何分配来划分。
堆栈(Stack)是⼀种先进先出的数据结构,在内存中,变量会被分配在堆栈上来进⾏操作。
堆(Heap)是⽤于为类型实例(对象)分配空间的内存区域,在堆上创建⼀个对象,会将对象的地址传递给堆栈上的变量(反过来叫变量指向此对象,或者变量引⽤此对象)。
值类型与引⽤类型的区别?
(1)、值类型的变量直接包含其数据
(2)、引⽤类型的变量则存储对象引⽤
对于引⽤类型,两个变量可能引⽤同⼀个对象,因此对⼀个变量的操作可能影响到另⼀个变量所引⽤的对象。
对于值类型,每个变量都有⾃⼰的数据副本,对于⼀个变量的操作不可能影响到另⼀个变量。
值类型隐式继承⾃System.ValueType,所以不能显⽰让⼀个结构继承⼀个类,C#不⽀持多继承。 
关于对象克隆的所设计到知识点
浅拷贝:是指将对象中的所有字段逐字复制到⼀个新对象
对值类型字段只是简单的拷贝⼀个副本到⽬标对象,改变⽬标对象中值类型字段的值不会反映到原始对象中,因为拷贝的是副本。实现浅拷贝需要使⽤Object类的MemberwiseClose⽅法⽤于创建⼀个浅表副本。
对引⽤类型字段则是指拷贝他的⼀个引⽤到⽬标对象,改变⽬标对象中引⽤类型字段的值会将它反映到原始对象中,因为拷贝的是指向堆是上的⼀个地址。
深拷贝:深拷贝与浅拷贝不同的是对于引⽤字段的处理,深拷贝会将在新对象中创建⼀个新的对象和原始对象字段相同(内容相同)的字段,也就是说这个引⽤和原始对象引⽤是不同,我们改变新对象这中这个字段的时候是不会影响到原始对象中对应字段的内容。须实现ICloneable接⼝中的Clone⽅法,且需要将被克隆对象加上[Serializable]特性。
引⽤类型的赋值、浅拷贝和深拷贝的区别
赋值:就是将原来对象的地址给新的对象拷贝⼀下即可。
浅拷贝:需要继承ICloneable接⼝(⽀持克隆,即⽤现有实例相同的值创建类的新实例),然后⽤MemberwiseClone⽅法(创建当前System.Object 的浅表对象)。但是需要注意的是MemberwiseClone拷贝⽅式,⾸先它是浅拷贝,⽅法是将所有的值类型字段拷贝⼀个副本,但是引⽤类型不会创建副本,仅仅是传递⼀个相同的地址给新对象,并且新对象和原对象指向的地址是⼀致的,这⾥有个问题就是string类型,但是实际上却是和值类型表现⼀致。
深拷贝:深拷贝与浅拷贝不同的是对于引⽤字段的处理,深拷贝会将在新对象中创建⼀个新的对象和原始对象字段相同(内容相同)的字段,也就是说这个引⽤和原始对象引⽤是不同,我们改变新对象这中这个字段的时候是不会影响到原始对象中对应字段的内容。须实现ICloneable接⼝中的Clone⽅法,且需要将被克隆对象加上[Serializable]特性。
2 List 的深拷贝
代码如下:
/// <summary>
/// Class Program
/// </summary>
class Program
{
/// <summary>
/// Defines the entry point of the application.
/// </summary>
/// <param name="args">The args.</param>
static void Main(string[] args)
{
List<Person> originalList = new List<Person>();
Person person = new Person();
person.Name = "zhangsan";
person.Age = 90;
Job job = new Job();
job.JobName = "开发⼯程师";
person.PersonJob = job;
originalList.Add(person);
person = new Person();
person.Name = "lisi2";
job = new Job();
job.JobName = "开发⼯程师";
person.PersonJob = job;
originalList.Add(person);
person = new Person();
person.Name = "3";
job = new Job();
job.JobName = "测试⼯程师";
person.PersonJob = job;
originalList.Add(person);
Console.WriteLine("原数据如下:");
for (int i = 0; i < originalList.Count; i++)
{
Console.WriteLine("Name:" + originalList[i].Name + ",JobName:" + originalList[i].PersonJob.JobName);
}
Console.WriteLine("--------------List深复制------------------");
List<Person> deepCopyList = Clone<Person>(originalList);
deepCopyList[1].Name = "lisi";
for (int i = 0; i < originalList.Count; i++)
{
Console.WriteLine("原数据:Name:" + originalList[i].Name + ",JobName:" + originalList[i].PersonJob.JobName);
Console.WriteLine("深复制后:Name:" + deepCopyList[i].Name + ",JobName:" + deepCopyList[i].PersonJob.JobName);            }
Console.WriteLine("----------------List赋值----------------");
List<Person> shallowCopyList = originalList;
shallowCopyList[2].Name = "amy";
shallowCopyList[2].PersonJob.JobName = "产品⼯程师";
Job modifyJob = new Job();
modifyJob.JobName = "UNKNOWN";
shallowCopyList[1].PersonJob = modifyJob;
for (int i = 0; i < originalList.Count; i++)
{
Console.WriteLine("原数据:Name:" + originalList[i].Name + ",JobName:" + originalList[i].PersonJob.JobName);
Console.WriteLine("浅复制:Name:" + shallowCopyList[i].Name + ",JobName:" + shallowCopyList[i].PersonJob.JobName);            }
param nameConsole.Read();
}
/// <summary>
/// Clones the specified list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="List">The list.</param>
/// <returns>List{``0}.</returns>
public static List<T> Clone<T>(object List)
{
using (Stream objectStream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(objectStream, List);
objectStream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(objectStream) as List<T>;
}
}
}
两个测试类代码如下:
/// <summary>
/// Class Person
/// </summary>
[Serializable]
public class Person
{
/// <summary>
/// Gets or sets the person job.
/// </summary>
/
// <value>The person job.</value>
public Job PersonJob
{
get;
set;
}
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name
{
get;
set;
}
/// <summary>
/// Gets or sets the age.
/// </summary>
/// <value>The age.</value>
public int Age
{
get;
set;
}
/// <summary>
/// Clones this instance.
/// </summary>
/// <returns>System.Object.</returns>
public object Clone()
{
BinaryFormatter formatter = new BinaryFormatter(null, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone));            MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, this);
stream.Position = 0;
object clonedObj = formatter.Deserialize(stream);
stream.Close();
return clonedObj;
}
}
/// <summary>
/// Class Job
/// </summary>
[Serializable]
public class Job
{
/// <summary>
/// Gets or sets the name of the job.
/// </summary>
/// <value>The name of the job.</value>
public string JobName
{
get;
set;
}
}
结果如下:
3 不⽤加Serializable的深复制⽅法
public static T DeepCopy<T>(T obj)
{
object retval;
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xml = new XmlSerializer(typeof(T));
xml.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);                retval = xml.Deserialize(ms);                ms.Close();
}
return (T)retval;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。