[c#基础]ICloneable接口
摘要
该接口使你能够创建现有对象的副本的自定义的实现。该接口只提供了,一个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实现深拷贝,对拷贝的副本进行操作,不影响它的原有的值,返回一个新的对象。
[c#基础]ICloneable接口的更多相关文章
- 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait
[源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...
- [.net 面向对象编程基础] (16) 接口
[.net 面向对象编程基础] (16) 接口 关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的.拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目 ...
- C#的System.ICloneable接口说明
System.ICloneable接口支持克隆,即用与现有实例相同的值创建类的新实例.msdn上的解释很简单,主要就是clone方法的实行,介绍深拷贝和浅拷贝,搞的很糊涂,那么到底是什么意思呢?看看下 ...
- spring中基础核心接口总结
spring中基础核心接口总结理解这几个接口,及其实现类就可以快速了解spring,具体的用法参考其他spring资料 1.BeanFactory最基础最核心的接口重要的实现类有:XmlBeanFac ...
- Go语言基础之接口
Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口介绍 在Go语言中接口(interface)是一种类型,一种抽象的类 ...
- C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态
C#基础--类/接口/成员修饰符,多态.重载.重写,静态和非静态 类/接口/成员修饰符 C#修饰符---接口: 接口默认访问符是internal接口的成员默认访问修饰符是public C#修饰符--类 ...
- Java基础十--接口
Java基础十--接口 一.接口的定义和实例 /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 8 ...
- Java基础-面向接口(interface)编程
Java基础-面向接口(interface)编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的“类 ...
- ICloneable接口 Clone 深拷贝 浅拷贝
需要字段本身也实现了深拷贝Clone.应用场景不多,意义不大. 1. 隐含式地要求其子类和引用类也要实现ICloneable接口,如果引用层次比较深类似一个网状或树形接口,增加复杂性. 2. 考虑给s ...
随机推荐
- 如何在DOS窗口复制和粘贴命令
在键盘上按下windows+R键,打开运行窗口. 在“打开”处输入cmd,并按下enter键,打开DOS窗口. 把鼠标移动到DOS窗口标题处,单击鼠标右键,选择属性. 把编辑选项处的“快速编辑模式”勾 ...
- 分布式调用技术 RPC VS REST
一 分布式调用大体上就分为两类,RPC式的,REST式的,两者的区别主要是就是: 1. RPC是面向动作的(方法调用) 2. REST是面向资源的(URL表示资源,HTTP动词表示动作) 从变现形式来 ...
- shell expect权威指南和实战
一.概述 我们通过Shell可以实现简单的控制流功能,如:循环.判断等.但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能.而expec ...
- 解决Javascript中$(window).resize()多次执行
有些时候,我们需要在浏览器窗口发生变化的时候,动态的执行一些操作,比如做自适应页面时的适配.这个时候,我们需要在窗口拖动的时候去执行代码.但是有些时候,执行的操作比较复杂,我们只希望在窗口拖动完毕之后 ...
- IE 浏览器 GET 请求缓存问题
问题描述 IE 浏览器(笔者使用的版本是 IE 11)在发起 GET 请求,当参数一样时,浏览器会直接使用缓存数据,这样对于实时性有要求的数据不适用.笔者在使用 Chrome 或 FF 时发现浏览器并 ...
- HTTP 1.1学习笔记
前言 由于HTTP 1自身的局限性,它不能很好的为用户提供性能良好的WEB服务.于1999年6月正式发布了HTTP1.1标准REC2616,它厘清了之前版本中很多有歧义的地方,而且还新增了很多重要的优 ...
- Zookeeper集群部署与配置(三)
在上一篇博客中我们讲解了<Zookeeper的单机配置>,此篇博客将继续介绍Zookeeper的集群部署与配置. 环境 集群配置的环境与单机配置的环境相同,唯一不同的就是集群是在多台服务器 ...
- java:从指定问价中读取80个字节写入指定文件中
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; public class F ...
- 【spring基础】spring与jdbc整合详解
先上一段简单示例 public class MyTemplate { private DataSource dataSource; public DataSource getDataSource() ...
- Kettle学习之Spoon简单使用
kettle学习之Spoon使用 2018-08-04 10:40:01 首先介绍两个博客入门: https://blog.csdn.net/zzq900503/article/details/785 ...