[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 ...
随机推荐
- Ex 3_25 图中每个顶点有一个相关价格..._十一次作业
(a)首先对有向无环图进行拓扑排序,再按拓扑排序的逆序依次计算每个顶点的cost值,每个顶点的cost值为自身的price值与相邻顶点间的cost值得最小值 (b)求出图中的每一个强连通分量,并把所有 ...
- NodeJs>------->>第三章:Node.js基础知识
第三章:Node.js基础知识 一:Node.js中的控制台 1:console.log.console.info 方法 console.log(" node app1.js 1> ...
- 基于axios创建的实例使用axios.all,报错:this.$http is not a function,但请求成功
报以下错误: 原因: axios实例没有all这个方法,all是axios的静态方法 解决方法: 以下方法不是最好的,还没找到更好的解决办法,目前先这样解决.
- spark简单总结—短小精悍
Spark是基于内存计算的大数据并行计算框架.因为其基于内存计算,较Hadoop中MapReduce计算框架具有更高的实时性,同时保证了高效容错性和可伸缩性.从2009年诞生于AMPLab到现在已经成 ...
- jquery----数据增删改
简单版本 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- poj2992 阶乘分解
/* 将C(n,k)质因数分解,然后约束个数按公式计算 */ #include<iostream> #include<cstring> #include<cstdio&g ...
- JavaScript错误:Maximum call stack size exceeded错误
错误的表面意思是,因为递归次数太多而内存溢出, 当然引起溢出的原因很多 找了下问题来源,发现引用了两个版本的jquery,在layout.cshtml母模块页中和视图中都引用了jq.导致循环调用,从而 ...
- poj 1321 棋盘问题(n行中放任意k行)
n*n的棋盘摆K的棋子,任意两个棋子不能在同一行同一列 Sample Input 2 1#. //# 可放.#4 4...#..#..#..#...-1 -1Sample Output 21 # i ...
- [转] 通过Ajax方式上传文件,使用FormData进行Ajax请求
通过传统的form表单提交的方式上传文件: <form id= "uploadForm" action= "http://localhost:8080/cfJAX_ ...
- 第四章: 4.1 logging模块 | 正则表达式
修改json数据然后写入json文件中 f = open('1234.json','r',encoding='utf-8') data = f.read() data1 = json.loads(da ...