[No0000178]改善C#程序的建议1:非用ICloneable不可的理由
好吧,我承认,这是一个反标题,实际的情况是:我找不到一个非用ICloneable不可的理由。事实上,接口ICloneable还会带来误解,因为它只有一个Clone方法。
我们都知道,对象的拷贝分为:浅拷贝和深拷贝。ICloneable仅有一个Clone方法使我们无法从命名的角度去区分到底是哪个拷贝。
浅拷贝:将对象的字段复制到副本(新的对象)中,同时将字段的值也赋值过去,但是引用类型字段只复制引用,而不是引用类型本身。这意味着,源对象引用类型字段的值改变了,会影响到副本中对应的值也改变;
深拷贝:将对象的字段复制到副本(新的对象)中,无论是值类型还是引用类型字段,都会复制类型本身及类型的值。这意味着,源对象引用类型字段的值改变了,不会影响到副本中对应的值;
于是问题来了,如果类型继承了ICloneable接口,那么类型中的Clone是浅拷贝还是深拷贝。微软的解释是:你既可以在Clone方法中实现浅拷贝,也可以实现深拷贝。那么,为什么不直接提供两个方法呢?比如:DeepClone或者ShallowClone。还是,一般类型的创建,只要实现了浅拷贝就不需要再实现深拷贝(或者反之),所以我们没有必要提供两个方法。
下面是一个既实现了浅拷贝也实现深拷贝的例子:
代码 [Serializable]
class Employee : ICloneable
{
publicstring IDCode { get; set; }
publicint Age { get; set; }
public Department Department { get; set; } #region ICloneable 成员 publicobject Clone()
{
returnthis.MemberwiseClone();
} #endregion public Employee DeepClone()
{
using (Stream objectStream =new MemoryStream())
{
IFormatter formatter =new BinaryFormatter();
formatter.Serialize(objectStream, this);
objectStream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(objectStream) as Employee;
}
} public Employee ShallowClone()
{
return Clone() as Employee;
}
}
实际上,ICloneable还带来一个问题(该问题Bill Wagner在Effcitive c#中曾经论述过),那就是:如果类型继承自ICloneable,但是同时它不是一个Sealed类型的话,它们的子类的默认Clone方法会带来BUG(子类的Clone方法会返回父类的副本,而不是子类本身)。这会逼迫所有的子类都重写Clone方法;
ICloneable的Clone方法的另一个问题是:它不是类型安全的,它返回的是Object,使用它的时候还设计到转型的问题,而我们自己实现的Clone方法却可以规避掉这个问题(如上文代码)。
综上所述,类型确实没必要继承ICloneable接口,如果类型本身需要实现拷贝功能,直接公开方法就行。如果在应用中你觉得确实必须实现这个接口的,来指正我吧。
[No0000178]改善C#程序的建议1:非用ICloneable不可的理由的更多相关文章
- 改善C#程序的建议1:非用ICloneable不可的理由
原文:改善C#程序的建议1:非用ICloneable不可的理由 好吧,我承认,这是一个反标题,实际的情况是:我找不到一个非用ICloneable不可的理由.事实上,接口ICloneable还会带来误解 ...
- [转]改善C#程序的建议4:C#中标准Dispose模式的实现
需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不 ...
- 改善C#程序的建议10:用Parallel简化Task
在命名空间System.Threading.Tasks下,有一个静态类Parallel简化了在同步状态下的Task的操作.Parallel主要提供了3个有用的方法:For.ForEach.Invoke ...
- 改善C#程序的建议8:避免锁定不恰当的同步对象
原文:改善C#程序的建议8:避免锁定不恰当的同步对象 在C#中让线程同步的另一种编码方式就是使用线程锁.所谓线程锁,就是锁住一个资源,使得应用程序只能在此刻有一个线程访问该资源.可以用下面这句不是那么 ...
- 改善C#程序的建议6:在线程同步中使用信号量
原文:改善C#程序的建议6:在线程同步中使用信号量 所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两 ...
- 改善C#程序的建议7:正确停止线程
原文:改善C#程序的建议7:正确停止线程 开发者总尝试对自己的代码有更多的控制.“让那个还在工作的线程马上停止下来”就是诸多要求中的一种.然而事与愿违,这里面至少存在两个问题: 第一个问题是:正如线程 ...
- 编写高质量代码--改善python程序的建议(六)
原文发表在我的博客主页,转载请注明出处! 建议二十八:区别对待可变对象和不可变对象 python中一切皆对象,每一个对象都有一个唯一的标识符(id()).类型(type())以及值,对象根据其值能否修 ...
- 编写高质量代码–改善python程序的建议(五)
原文发表在我的博客主页,转载请注明出处! 建议二十三:遵循异常处理的几点基本原则 python中常用的异常处理语法是try.except.else.finally,它们可以有多种组合,语法形式如下: ...
- 编写高质量代码--改善python程序的建议(八)
原文发表在我的博客主页,转载请注明出处! 建议四十一:一般情况下使用ElementTree解析XML python中解析XML文件最广为人知的两个模块是xml.dom.minidom和xml.sax, ...
随机推荐
- 解决《UNIX环境高级编程》(APUE)示例代码的编译问题
转自 http://cunsheng.sinaapp.com/?p=360 APUE中示例很多, 把这些源码拿来跑跑调调对学习理解有着莫大的帮助, 随书网站就提供了源码下载, 不过我自己在Linux和 ...
- 基于CentOS搭建VNC远程桌面服务
系统要求:CentOS 7.2 64 位操作系统 安装.启动 VNC VNC 远程桌面原理 名词解释: Xorg:在 Linux 用户中非常流行,已经成为图形用户程序的必备条件,所以大部分发行版都提供 ...
- 你被R语言的=和<-搞昏了头吗
学习R有一周了,心中一直有一个困惑,关于= 和 <-,今晚决定搞定它! 迄今为止用到最多的函数是matrix() 和c(),就用他们说起! 之前学了四五门语言,对于=赋值已经成了惯性,下面是 ...
- C#调用存储过程详解(带返回值、参数输入输出等)
CREATE PROCEDURE [dbo].[GetNameById] @studentid varchar(8), @studentname nvarchar(50) OUTPUT AS BEGI ...
- MDK-ARM输出HEX文件重命名设置
输出的可执行文件和库的名称就是在这里定义.比如我们常见输出Hex文件,其名称就是这里定义的.
- python开发-与其他语言的比较
1.关于函数 1)不需要指定返回类型,不需要指定是否有返回值,每个函数都有返回值,没有的话,就返回None 2)参数也可以不指定类型,可以有默认参数,但是必须放到最后,调用的时候指定参数的值,和顺序无 ...
- Spring MVC异常统一处理的三种方式
Spring 统一异常处理有 3 种方式,分别为: 使用 @ ExceptionHandler 注解 实现 HandlerExceptionResolver 接口 使用 @controlleradvi ...
- Git -- 自定义git样式
在安装Git一节中,我们已经配置了user.name和user.email,实际上,Git还有很多可配置项. 比如,让Git显示颜色,会让命令输出看起来更醒目: $ git config --glob ...
- 三、主流区块链技术特点及Hyperledger Fabric V1.0版本特点
一.Hyperledger fabric V1.0 架构 1.逻辑架构: 2.区块链网络 3.运行时架构 二.架构总结 1.架构要点 分拆Peer的功能,将Blockchain的数据维护和共识服务进行 ...
- Angular4学习笔记(二)-在WebStorm中启动项目
点击配置 创建 选择命令 package.json 运行 查看运行结果