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);
} Console.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;
}

  

作者:BestNow
出处:http://www.cnblogs.com/BestNow/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 

C# List的深复制(转)的更多相关文章

  1. 学习笔记--C#深复制和浅复制

    参考博客:http://www.cnblogs.com/nliao/archive/2012/11/18/2776114.html 例子网上都有很多,我也就不列了. 其实很久以前就明白了这两者的区别, ...

  2. iOS 浅复制和深复制的深层理解,含示例

    转载:https://www.zybuluo.com/MicroCai/note/50592 版权归 @MicroCai 所有 以下是正文: 浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 ( ...

  3. PHP浅复制与深复制

    原文链接:http://www.orlion.ga/731/ php用clone复制对象有一个问题,下面用代码来说明问题: class Foo{ public $bar; public $name; ...

  4. .Net深复制、浅复制

    在.Net,大家都知道引用类型的深复制.浅复制吧. ,一般int等值类型是值类型(复制时是直接传值),一般的类(List<T>,Class)是引用类型(复制时传地址),默认是浅复制.若ob ...

  5. python中深复制与浅复制

    转载:http://blog.csdn.net/vicken520/article/details/8227524 java中也经常碰见这种问题.时间原因就不写java方面啦 Python深复制浅复制 ...

  6. javascript中关于深复制与浅复制的问题

    在javascript中,变量的类型分为基本类型和引用类型. 对于基本类型的变量来说,值的复制以及作为函数参数实参传递的过程都是值的复制传递,换句话说,是会在内存中开辟出一个新空间用于存放新的值的.这 ...

  7. js 对象深复制,创建对象和继承

    js 对象深复制,创建对象和继承.主要参考高级编程第三版,总结网上部分资料和自己的代码测试心得.每走一小步,就做一个小结. 1.对象/数组深复制 一般的=号传递的都是对象/数组的引用,如在控制台输入 ...

  8. C++学习基础七——深复制与浅复制

    一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深 ...

  9. javascript中的浅复制和深复制

    //浅复制:实现基本类型的复制没有问题,但是复制的是引用类型的话,则修改child将会修改parent function extend(parent,child){ var child = child ...

  10. Java-clone浅/深复制

    Object中的clone方法为复制当前对象 protected native Object clone() throws CloneNotSupportedException; 想要使用这个方法需要 ...

随机推荐

  1. DB2 的事务日志

    1.     DB2事务日志:DB2的日志分主日志和次日志,主日志是在数据库第一次被连接和激活时创建的,而次日志是当写满所有的主日志后,才动态分配次日志,主日志和次日志受设置个数的制约,当配置的所有主 ...

  2. ShardedJedis的分片原理

    ShardedJedisPool xml配置: <bean id="shardedJedisPool" class="redis.clients.jedis.Sha ...

  3. js判断数组,对象是否存在某一未知元素

    1.对象 var obj = { aa:'1111', bb:'2222', cc: '3333' }; var str='aa'; if(str in obj){ console.log(obj[s ...

  4. python中字符串连接的四种方式

    以下实例展示了join()的使用方法 #!/usr/bin/python str = "-"; seq = ("a", "b", " ...

  5. spring cloud学习(六)Spring Cloud Config

    Spring Cloud Config 参考个人项目 参考个人项目 : (希望大家能给个star~) https://github.com/FunriLy/springcloud-study/tree ...

  6. linux create a process

    When the system starts up it is running in kernel mode and there is, in a sense, only one process, t ...

  7. Kafka消费者APi

    Kafka客户端从集群中消费消息,并透明地处理kafka集群中出现故障服务器,透明地调节适应集群中变化的数据分区.也和服务器交互,平衡均衡消费者. public class KafkaConsumer ...

  8. 网络协议栈学习(一)socket通信实例

    网络协议栈学习(一)socket通信实例 该实例摘自<linux网络编程>(宋敬彬,孙海滨等著). 例子分为服务器端和客户端,客户端连接服务器后从标准输入读取输入的字符串,发送给服务器:服 ...

  9. 2018-北航-面向对象567次OO作业分析与小结

    设计策略及其变化 第五次作业-多线程电梯 在这次作业一开始的大部分时间,我一直想着怎样设计最为完美,完全使用BlockingQueue,导致交作业前发现设计并不能满足指导书的要求.最后仓皇之中加了一个 ...

  10. 配置ssh互信的一个小问题记录

    在我们安装集群软件时,经常需要配置机器之间的互信,每个人也有一套自己熟悉的方法. 但是在今天配置互信过程中,发现操作过程还是一样,但是就是不能互信,通过查找资料解决了,做一下记录. 我经常使用的方式: ...