最近在学习Bill Wagner的书籍:《Effective C#:50 Specific Ways to Improve Your C#》,虽然是一本很早的书了,但是感觉很实用,并且跟国内出版的许多“提高代码质量的XXX条建议"之类的书籍相比,其实大部分的解释都大同小异,所以准备以此为基础,决定对学习过程中的理解做一些记录。

ICloneable接口,在MSDN上的解释很简单:支持克隆,即创建一个与原实例拥有相同成员值的新实例副本。ICloneable接口只有一个成员方法,Clone()。一切看起来没有什么复杂的,但是使用过该接口之后,你就会发现潜藏的问题不少。

既然是对对象的拷贝功能,那就涉及到了深拷贝和浅拷贝的问题。

浅拷贝:将对象中的所有字段复制到新的对象(副本)中。其中,值类型字段的值被复制到副本中后,在副本中的修改不会影响到源对象对应的值。而引用类型的字段被复制到副本中的是引用类型的引用,而不是引用的对象,在副本中对引用类型的字段值做修改会影响到源对象本身。

深拷贝:将对象中的所有字段复制到新的对象中。不过,无论是对象的值类型字段,还是引用类型字段,都会被重新创建并赋值,对于副本的修改,不会影响到源对象本身。

由于只有一个Clone方法,那么调用者在调用第三方提供的Clone方法的时候,也就不能确认自己得到的拷贝对象,到底是深拷贝还是浅拷贝。MSDN上也提到:Clone方法不能明确告知返回的对象到底是深拷贝,浅拷贝,还是介于二者之间的拷贝。许多专家也对这种现象予以指责。同时,本人在使用ICloneable的时候,想到,既然只是拷贝的问题,那么提供浅拷贝和深拷贝两个公共方法就行了,为什么还要用Cloneable呢?有解释是微软建议用类型继承ICloneable接口的方式明确告诉调用者:该类型可以被拷贝。不知道还有没有其它的解释呢。

使用ICloneable的第二个问题,就是如果基类继承了ICloneable接口,并且非Sealed类型,那么它的所有派生类都需要实现Clone方法。否则,用派生类对象调用Clone方法,返回的对象将会是基类Clone方法创建的对象,这就给派生类带来了沉重的负担。所以应尽量避免在非密封类中实现ICloneable。

第三个需要注意的问题,就是Clone方法必须对返回值装箱,让其变成一个System.Object引用,也就是说Clone方法返回值是非类型安全的。不仅如此,随后,调用者还需要拆箱,进行对象转型操作。

第四个问题,就是由于ICloneable使用的结果经常是弊大于利,所以.Net Framework在升级支持泛型时没有添加ICloneable<T>。

根据ICloneable使用上的问题,Bill Wagner建议:对于值类型,永远都不要实现ICloneable,直接使用赋值操作即可。对于那些叶子类,仅在真正需要复制操作时再添加ICloneable支持。对于那些派生类很有可能会支持ICloneable的基类来说,你可以创建一个受保护的复制结构函数,供派生类使用。在其他的各种情况下,应尽量避免使用ICloneable。

参考资料:Bill Wagner,《Effective C#:50 Specific Ways to Improve Your C#》

陆敏技 博客:http://www.cnblogs.com/luminji/archive/2011/02/02/1948826.html

MSDN blogs:http://blogs.msdn.com/b/mrtechnocal/archive/2009/10/19/why-not-icloneable-t.aspx

转载于:https://www.cnblogs.com/ByronsHome/p/3366596.html

Effective C#:避免使用ICloneable接口相关推荐

  1. C#的System.ICloneable接口说明

    原理 如果我们有两个值类型的变量,将其中一个变量的值赋给另一个,实际上会创建该值的一个副本,这个副本与原来的值没有什么关系--这意味着改变其中一 个的值不会影响另一个变量的值.而如果是两个引用类型的变 ...

  2. [c#基础]ICloneable接口

    摘要 该接口使你能够创建现有对象的副本的自定义的实现.该接口只提供了,一个Clone方法,实现对象的浅拷贝.有浅拷贝,那么就有相对应的深拷贝.但该接口并没有对我们提供,需要我们自己实现. 什么是浅拷贝 ...

  3. Effective java笔记3--类和接口2

    三.接口优于抽象类 java提供两种机制,可以用来定义一个允许多个实现的类型:接口和抽象类.由于java只允许单继承,所以,抽象类作为类型定义受到了极大的限制. 已有的类可以很容易被更新,以实现新的接 ...

  4. 读书笔记 effective c++ Item 18 使接口容易被正确使用,不容易被误用

    1. 什么样的接口才是好的接口 C++中充斥着接口:函数接口,类接口,模板接口.每个接口都是客户同你的代码进行交互的一种方法.假设你正在面对的是一些"讲道理"的人员,这些客户尝试把 ...

  5. Effective java笔记3--类和接口1

    一.使类和成员的可访问能力最小化 要想区别一个设计良好的模块与一个设计不好的模块,最重要的因素是,这个模块对于外部的其他模块而言,是否隐藏了内部的数据和其他的实现细节.一个设计良好的模块会隐藏所有的实 ...

  6. 读书笔记 effective c++ Item 34 区分接口继承和实现继承

    看上去最为简单的(public)继承的概念由两个单独部分组成:函数接口的继承和函数模板继承.这两种继承之间的区别同本书介绍部分讨论的函数声明和函数定义之间的区别完全对应. 1. 类函数的三种实现 作为 ...

  7. 带你快速看完9.8分神作《Effective Java》—— 类和接口篇

  8. 【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复

    前言 虽然在.Net Framework 中我们不必考虑内在管理和垃圾回收(GC),但是为了优化应用程序性能我们始终需要了解内存管理和垃圾回收(GC).另外,了解内存管理可以帮助我们理解在每一个程序中 ...

  9. 书籍推荐:《More Effective C#》

    很多年前看过Bill Wagner的<Effective C#>第一版,涵盖了C#2.0相关语言特性的最佳实践,教我们怎样更优雅地去编写C#代码,当时觉得受益匪浅.最近拿到了<Mor ...

最新文章

  1. PolarSSL 1.2.0 发布,SSL 加密库
  2. 人体上身各部位图_【肝货】画好人体结构,你还需要了解这些
  3. Python 技术篇-不使用os模块遍历文件夹,pathlib库获取直接下级文件和所有下级文件
  4. 系统诊断概述-如何通过windbg来dump特定process的memory.
  5. Boost:boost::asio模块的引用计数测试程序
  6. 语言基础之description方法
  7. [转载]PSCAD调用MATLAB/SIMULINK之接口元件设计
  8. 实现klib_使用klib加速数据清理和预处理
  9. intern_充分利用Outreachy Intern申请流程
  10. 三相阻容降压供电DCDC电源
  11. Vue+Mock.js模拟登录和表格的增删改查
  12. WPF4.5 Cockbook - Chapter8(Style, Triggers and Control Template)
  13. python程序出现了异常会执行哪个语句,python中的异常是什么?应该怎么处理异常?...
  14. curl get请求传递参数_curl 命令
  15. CentOS7.9下实战安装MySQL5.7
  16. 计算机网络基础知识题,计算机网络基础知识试题及答案
  17. HI3559A源码包编译及问题解决
  18. 微信小程序自适应横屏全屏显示(以PPT为例)
  19. 第五套人民币是大众收藏的机会
  20. linux安装vscode(中标麒麟+龙芯CPU)

热门文章

  1. GenericUDAF使用流程记载(转载+自己整理)
  2. The number of requested virtual cores per node 3 exceeds the maximum number of virtual cores 2
  3. Django报错NameError: name 'ListView' is not defined
  4. sudo gedit出现No protocol specified
  5. mysql分隔符声明_MySQL分隔符发生错误时?
  6. linux as86,记linux_centOS安装as86过程
  7. 第 2 章 OpenStack 架构 - 017 - 部署 DevStack
  8. 理解JWT(JSON Web Token)认证及python实践
  9. U-Mail邮件网关鉴伪防窃杜绝“家贼”
  10. java synchronized wait