[c#基础]ICloneable接口
2024-08-26 18:46:12
摘要
该接口使你能够创建现有对象的副本的自定义的实现。该接口只提供了,一个Clone方法,实现对象的浅拷贝。有浅拷贝,那么就有相对应的深拷贝。但该接口并没有对我们提供,需要我们自己实现。
什么是浅拷贝与深拷贝?
浅拷贝
将对象的字段复制到新的对象副本中,同时将字段的值也复制过去,但引用类型值复制引用,而不是引用类型本身,也就是,如果源对象的引用类型的字段的值改变了,拷贝的对象的对应的引用类型的字段也会跟着变化。
深拷贝
将对象的字段复制到新的对象副本中,无论是值类型还是引用类型的字段,都会复制类型本身及值。但,源对象的值变化,并不会影响副本中的对应的值。
一个例子
浅拷贝
using Newtonsoft.Json;
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary; namespace Wolfy.CloneDemo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("创建新对象:");
Person p = new Person() { Name = "wolfy", Id = , Address = new Address { City = "北京", Details = "北京 海淀区" } };
Console.WriteLine(p.ToString());
Console.WriteLine("克隆对象:");
Person p2 = (Person)p.Clone();
Console.WriteLine(p2.ToString());
var result = object.ReferenceEquals(p, p2);
Console.WriteLine("p ReferenceEquals p2:" + result);
Console.WriteLine("此时修改p对象,是否会影响p2对象?");
p.Name = "wolfy2";
p.Id = ;
p.Address.City = "上海";
Console.WriteLine("p:" + p.ToString());
Console.WriteLine("p2:" + p2.ToString()); Console.Read();
} }
[Serializable]
class Person : ICloneable
{
/// <summary>
/// 值类型
/// </summary>
private int _id;
/// <summary>
/// 特殊的引用类型
/// </summary>
private string _name;
private Address _address;
public int Id { get => _id; set => _id = value; }
public string Name { get => _name; set => _name = value; }
public Address Address { get => _address; set => _address = value; } public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
public object Clone()
{
/*
MemberwiseClone方法创建的新对象,然后将当前对象的非静态字段复制到新的对象创建的浅表副本。
如果字段是值类型,则执行字段的按位复制。 如果字段是引用类型,引用将复制,但被引用的对象不;
因此,原始对象和其克隆引用同一对象。
例如,考虑对象称为 X 引用对象 A 和 B,反过来,引用对象 c。
X 的浅表副本创建新的对象 X2 也引用对象 A 和 b。与此相反,
X 的深层副本创建新对象 X2 引用 A2 和 B2,
是的一个副本的新对象并 B.B2,
反过来,引用新对象 C2,这是 C 的副本。该示例说明浅和深层复制操作之间的差异。 有很多方法可以实现深层复制操作,如果浅表复制操作由MemberwiseClone方法并不满足你的需求。
这些要求包括: 调用类构造函数要复制可以使用来自第一个对象的属性值创建第二个对象的对象。
这假定,对象的值完全由其类构造函数中定义。 调用MemberwiseClone方法创建一个对象,
对象的浅表副本并将其值是与原始对象的任何属性或其值是引用类型的字段相同的新对象。
DeepCopy方法在示例中演示了此方法。 序列化对象是较深复制,,然后将序列化的数据还原到另一个对象变量。 使用具有递归反射来执行深层复制操作。
*/
return this.MemberwiseClone();
}
public object DeepClone()
{
using (Stream objectStream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(objectStream, this);
objectStream.Seek(, SeekOrigin.Begin);
return formatter.Deserialize(objectStream) as Person;
}
}
}
[Serializable]
class Address
{
private string _city;
private string _details; public string City { get => _city; set => _city = value; }
public string Details { get => _details; set => _details = value; }
} }
如上图所示,浅拷贝,值类型的并不会相互影响,但是引用类型的Address会跟着改变。浅拷贝,在对引用类型的字段时,会拷贝指向该对象的引用。
深拷贝
将
Person p2 = (Person)p.Clone();
改为
Person p2 = (Person)p.DeepClone();
结语
在实际项目中,这个接口自己是没用过。在看c#相关的文章的时候,看到了该接口的介绍,一篇文章了解下。如果非要说应用场景的话,比如,如果一个方法参数是一个引用类型,你需要在方法中对其进行操作,但又不想改变它原有的值,可以实现该接口,在clone实现深拷贝,对拷贝的副本进行操作,不影响它的原有的值,返回一个新的对象。
最新文章
- ThreadPoolTimer -延迟执行, 周期执行
- js 作用域
- shell中判读文件存在的方法
- Zepto 实现checkbox全选与全不选状态切换
- python 之post、get与cookie实战
- TypeScript 0.9.1 发布,新增 typeof 关键字
- .net matlab 数据类型转换
- centos上安装jdk环境
- x+2y+3z=n的非负整数解数
- Oracle11g服务及实例
- node 裁剪图片
- King&#39;s Quest - poj 1904(强连通分量+外挂输入输出)
- o2o
- 如何高效的进行WebService接口性能测试
- influxDB+grafana安装配置及邮件告警发送配置
- IP通信基础学习第六周(下)
- multiprocessing- 基于进程的并行性
- HTTP 协议(一)之基本概念入门
- Android性能测试--内存
- net 反射30分钟速成
热门文章
- lr使用linux Generator测试https莫名报 SSL protocol error when attempting to connect with host
- cf1108e 线段树区间更新+扫描线
- C/S权限系统(一)
- django 如何动态使用Q查询函数
- Hibernate之关联关系映射(一对一主键映射和一对一外键映射)
- spring配置redis注解缓存
- SQL存储过程使用参考代码
- Codeforces 1102F Elongated Matrix 状压dp
- html的header结构和实例
- 096实战 在windows下新建maven项目