《Effective C#》 Item 27:避免使用 ICloneable接口

Effective C# Item 27: Avoid ICloneable

      ICloneable听起来不错:通过它我们就可以让类型支持拷贝。但是我们的类往往并不是独立存在的。一旦我们确定要支持ICloneable,那么它的所有派生类也需要实现这个接口。内部的所有成员也需要支持ICloneable或者其它创建拷贝的机制。要实现深克隆经常会带来很多的问题。在理论上ICloneable是用来解决这些克隆问题的:它可以支持浅克隆或者深克隆。浅克隆创建一个新的对像,对像成员的内容都是原内容的拷贝。对于引用类型来说,新的对像和原对像引用的地址是一样的。而深克隆也是创建一个新对像并拷贝其成员。所有的引用类型都被递归克隆,而不再引用原对像成员。对于.Net内建值类型,例如int来说,这两种克隆方式的结果没有区别。究竟支持哪种要取决于我们的类。但是混合了潜克隆和深克隆机制的类会给我们造成一些错误。一旦掉进了ICloneable的陷阱,就很难全身而退了。一般情况下尽量将类创建得简单,避免使用ICloneable。这样既便于使用,也便于实现。

      任何只包含内建类型成员的值类型是不需要支持ICloneable的。简单的拷贝值到结构体中比使用Clone()更加高效。Clone()在返回值时需要装箱操作,在使用返回值时又需要对其拆箱。

      那么如果值类型中包含引用类型呢?最常见的例子就是一个结构体中包含string型成员:

public struct ErrorMessage

{

    private int errCode;

    private int details;

    private string msg;

}

 

string是一个特例因为它是不可变类型(参见 Item7: Prefer Immutable Atomic Value Types)。它不会引发一般的引用类型造成的麻烦。因为一旦msg的值变化了,就代表它指向了一个新的string对像的引用。

      如果结构中包含其它的引用类型,那么情况就会复杂的多。而且这种情况也是很常见的。当我们使用内建的拷贝操作(最简单的=操作符)时,创建的是一个潜克隆对像,其中的引用类型成员同原结构体中的成员指向同一个对像。如果要创建深拷贝,我们首先要确定结构中的引用类型是否支持深拷贝。

      我们使用ICloneable的时候必须谨慎,因为我们需要考虑到派生类的情况。先看下面这个例子:

 

class BaseType

    {

        private string _label;

        private int[] _values;



        protected BaseType()

        {

            _label = "class name";

            _values = new int[10];

        }



        protected BaseType(BaseType right)

        {

            _label = right._label;

            _values = right._values.Clone() as int[];

        }

    }



    sealed class Derived : BaseType, ICloneable

    {

        private double[] _dValues = new double[10];



        public Derived()

        {

            _dValues = new double[10];

        }



        private Derived(Derived right)

            : base(right)

        {

            _dValues = right._dValues.Clone as int[];

        }



        ICloneable 成员#region ICloneable 成员



        public object Clone()

        {

            Derived rVal = new Derived(this);

            return rVal;

        }



        #endregion

    }
上例中基类没有实现ICloneable,它提供了一个受保护的构造函数来让派生类拷贝基类成员。
对于声明为sealed的派生类可以在必要时实现ICloneable。这样虽然基类提供了对克隆的必要支持,
也不要求所有的派生类都实现克隆。
      ICloneable虽然有它的优势,但是也会造成很多麻烦。
永远不要让值类型支持ICloneable。尽量避免在不必要的情况下使用ICloneable接口。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值