[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 ...
随机推荐
- 转载:Linux操作系统(1.3.1)《深入理解Nginx》(陶辉)
原文:https://book.2cto.com/201304/19611.html 1.3 准备工作 由于Linux具有免费.使用广泛.商业支持越来越完善等特点,本书将主要针对Linux上运行的Ng ...
- Linux设备模型:基础篇
linux提供了新的设备模型:总线(bus).设备(device).驱动(driver).其中总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连:设备是对于一个设备的详细信息描述,驱动 ...
- PYTHON-操作系统基础-2-练习
#===============================================# # 1.简述cpu.内存.硬盘的作用# cpu是人的大脑,负责控制全身和运算# 内存是人的记忆,负责 ...
- java多线程快速入门(十五)
使用violate关键字解决了变量的可见性问题(volatile让多线程刷新falg的值) package com.cppdy; class MyThread11 extends Thread { / ...
- Application.ProcessMessages; 的重要性
https://files.cnblogs.com/files/del88/登陆光标_悬赏50元.zip ----------------------------------------------- ...
- Django2.0使用dos新建项目
由于本人的Pycharm不能直接生成Django项目,所以用命令行来生成项目,搭建此项目,请先搭建好环境 环境:PyCharm Python3.5.2 Django 2.0 1.使用dos进入工作目 ...
- java根据word模板导出word文件
1.word模板文件处理,如下图所示在word 文档中填值的地方写入占位变量 2.将word文档另存为xml文件.编辑如下图,找到填写的占位,修改为${bcrxm}格式 3.将文件后缀名改为.ftl文 ...
- hdu 1258 从n个数中找和为t的组合 (DFS)
题意:首先给你一个t,然后是n,后面输入n个数,然后让你求的是n个数中和为t的序列总共有多少种,把他们按从左到右的顺序输出来. Sample Input4 6 4 3 2 2 1 15 3 2 1 1 ...
- 简易图书管理系统(主要是jsp的练习)
1:首先设计用户表和图书表,设计的字段和类型如下图所示 1.1:用户表user 1.2:图书表book 2:第二写实体类user.java和book.java package com.bie.po; ...
- CentOS6.8安装360 pika
1.安装依赖包 yum install snappy-devel bz2 libzip-dev libsnappy-dev libprotobuf-dev libevent-dev protobuf- ...