在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
最近在学习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 |
请发表评论