zoukankan      html  css  js  c++  java
  • Effective C# 学习笔记(三十二)避免使用ICloneable接口

    实现ICloneabl接口听起来很美,不是么?还真不是,你要是为某个类实现了ICloneable接口,你就得为它的子类和相关的深拷贝和浅拷贝担心,注意每一属性的可被复制的深浅及其被复制的必要性。这看起来是多么大的一个工程,也许远远超出你的想象。

     

    首先来看纯值类型(不包含引用类型属性的值类型),这种类型没有必要实现ICloneable接口,因为这种类型只需为新对象赋值,就可将值赋值到新对象中,调用Clone方法的话,即让返回值装了箱,你还得在给新对象赋值时进行拆箱,性能上得不偿失。

     

    而对于包含引用类型的值类型及引用类型来说,应该对该值类型的引用类型属性进行分析,以保证整个类型的Copy逻辑是一个深拷贝的逻辑。而且对于引用类型实现ICloneable接口,其子类的实现也是一个很大包袱。看如下代码:

    class BaseType : ICloneable

    {

    private string label = "class name";

    private int[] values = new int[10];

    public object Clone()

    {

    BaseType rVal = new BaseType();

    rVal.label = label;

    for (int i = 0; i < values.Length; i++)

    rVal.values[i] = values[i];

    return rVal;

    }

    }

    class Derived : BaseType

    {

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

    static void Main(string[] args)

    {

    Derived d = new Derived();

    Derived d2 = d.Clone() as Derived;

    if (d2 == null)

    Console.WriteLine("null");

    }

    }

    上面的代码的父类BaseType实现了ICloneable,但子类调用父类的Clone方法时返回的对象为BaseType,所以上面的方法对于d2的赋值只能是null ,因为他不能转换为Derived类型。

     

    而正确的实现方式应该如下,让子类实现ICloneable接口,并让父类实现一个protected修饰的以自身类型为参数的构造函数,供子类在其Clone方法中调用,以初始化Copy对象的父类的值,代码如下:

     

    class BaseType

    {

    private string label;

    private int[] values;

    protected BaseType()

    {

    label = "class name";

    values = new int[10];

    }

    // Used by devived values to clone

    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];

    }

    // Construct a copy

    // using the base class copy ctor

    private Derived(Derived right) :base(right)

    {

    dValues = right.dValues.Clone()

    as double[];

    }

    public object Clone()

    {

    //这里通过重载的私有构造函数来创建Copy的父类中的属性和子类中的属性

    Derived rVal = new Derived(this);

    return rVal;

    }

    }

     

    注意:这里的子类用了sealed关键字,也就是提醒你适可而止,否则随着继承的深度加深你要做的事就会越来越多,还是避免使用其为好。

  • 相关阅读:
    c
    罗扎诺夫高效记忆音乐【推荐试试】
    通过信息系统项目管理师最高可申领补贴2000元
    人事考试网【您有新信息】浙江人事考试网_浙江省公务员考试网_2017浙江公务员考试_中公浙江
    几种需求管理工具(转)_伊处_新浪博客
    PLM_百度百科
    统御软件 (oKit)| 项目管理软件,项目管理咨询,项目需求管理工具,集成研发管理平台 ——管理咨询与实施工具 一站式项目管理解决方案
    Oracle PLM
    Oracle PLM
    Oracle PLM
  • 原文地址:https://www.cnblogs.com/haokaibo/p/2108985.html
Copyright © 2011-2022 走看看