为了账号安全,请及时绑定邮箱和手机立即绑定

复制构造函数与Clone()

/ 猿问

复制构造函数与Clone()

C#
慕斯709654 2019-12-21 11:33:45

在C#中,向类添加(深度)复制功能的首选方法是什么?是应该实现副本构造函数,还是应该派生ICloneable并实现该Clone()方法?

查看完整描述

3 回答

?
幕布斯7119047

您不应该源自ICloneable。


原因是,当Microsoft设计.net框架时,他们从未指定Clone()方法ICloneable是深克隆还是浅克隆,因此接口在语义上被破坏,因为调用者将不知道该调用将深克隆还是浅克隆对象。


相反,您应该使用(和)方法定义自己的IDeepCloneable(和IShallowCloneable)接口。DeepClone()ShallowClone()


您可以定义两个接口,一个具有通用参数以支持强类型克隆,而一个接口则不具有弱类型克隆功能,以供您处理不同类型的可复制对象的集合时使用:


public interface IDeepCloneable

{

    object DeepClone();

}

public interface IDeepCloneable<T> : IDeepCloneable

{

    T DeepClone();

}

然后您将像这样实现:


public class SampleClass : IDeepCloneable<SampleClass>

{

    public SampleClass DeepClone()

    {

        // Deep clone your object

        return ...;

    }

    object IDeepCloneable.DeepClone()   

    {

        return this.DeepClone();

    }

}

通常,我更喜欢使用描述的接口,而不是使用复制构造函数,这样可以使意图保持清晰。复制构造函数可能被假定为是深层克隆,但是显然没有使用IDeepClonable接口那么明显。


《 .net 框架设计指南》和Brad Abrams的博客中对此进行了讨论。


(我想如果您正在编写一个应用程序(而不是框架/库),那么可以确保团队之外的任何人都不会调用您的代码,这无关紧要,您可以分配“深层克隆”到.net ICloneable接口,但是您应该确保在团队中对此进行了充分的文档记录和理解。我个人会遵守框架准则。)


查看完整回答
反对 回复 2019-12-21
?
天涯尽头无女友

在C#中,向类添加(深度)复制功能的首选方法是什么?是应该实现复制构造函数,还是应该从ICloneable派生并实现Clone()方法?


ICloneable正如其他人提到的那样,它的问题在于它没有指定是深拷贝还是浅拷贝,这使得它实际上不可用,并且在实践中很少使用。它也返回object,这很痛苦,因为它需要大量的转换。(尽管您在问题中特别提到了类,但ICloneable在structrequire box上实现。)


复制构造者也遭受ICloneable的问题之一。复制构造函数是在进行深层复制还是浅层复制,这一点并不明显。


Account clonedAccount = new Account(currentAccount); // Deep or shallow?

最好创建一个DeepClone()方法。这样,意图就很清楚了。


这就提出了一个问题,它应该是静态方法还是实例方法。


Account clonedAccount = currentAccount.DeepClone();  // instance method

要么


Account clonedAccount = Account.DeepClone(currentAccount); // static method

有时候,我稍微偏爱静态版本,因为克隆似乎是对对象执行的操作,而不是对象正在执行的操作。无论哪种情况,在克隆属于继承层次结构的对象时都将要处理一些问题,而如何解决这些问题最终可能会推动设计。


class CheckingAccount : Account

{

    CheckAuthorizationScheme checkAuthorizationScheme;


    public override Account DeepClone()

    {

        CheckingAccount clone = new CheckingAccount();

        DeepCloneFields(clone);

        return clone;

    }


    protected override void DeepCloneFields(Account clone)

    {

        base.DeepCloneFields(clone);


        ((CheckingAccount)clone).checkAuthorizationScheme = this.checkAuthorizationScheme.DeepClone();

    }

}


查看完整回答
反对 回复 2019-12-21
?
呼唤远方

我建议在复制方法上使用复制构造函数,主要是因为复制方法会阻止您创建readonly原本应该使用构造函数的字段。


如果需要多态克隆,则可以通过调用复制构造函数在实现的基类中添加abstract或virtual Clone()方法。


如果您需要多种拷贝(例如:深/浅),则可以在拷贝构造函数中使用参数指定它,尽管根据我的经验,我通常需要混合使用深拷贝和浅拷贝。


例如:


public class BaseType {

   readonly int mBaseField;


   public BaseType(BaseType pSource) =>

      mBaseField = pSource.mBaseField;


   public virtual BaseType Clone() =>

      new BaseType(this);

}


public class SubType : BaseType {

   readonly int mSubField;


   public SubType(SubType pSource)

   : base(pSource) =>

      mSubField = pSource.mSubField;


   public override BaseType Clone() =>

      new SubType(this);

}


查看完整回答
反对 回复 2019-12-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信