Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 创建新实例时如何在基类中使用Copy方法_C# - Fatal编程技术网

C# 创建新实例时如何在基类中使用Copy方法

C# 创建新实例时如何在基类中使用Copy方法,c#,C#,我有一个类B,它派生自另一个类a。类a实现了一个复制方法。如何在类B中实现使用.Copy()的复制方法 我没有使用克隆以及为什么我想拥有这种继承结构,有一些原因(可能不是很好的原因) class A { ... properties ... public A Copy() { ...copy properties.... } } class B : A { ... one extra property ... public B

我有一个类B,它派生自另一个类a。类a实现了一个复制方法。如何在类B中实现使用.Copy()的复制方法

我没有使用克隆以及为什么我想拥有这种继承结构,有一些原因(可能不是很好的原因)

class A 
{
    ... properties ...
    public A Copy()
    {
        ...copy properties....
    }
}

class B : A 
{
    ... one extra property ...
    public B Copy()
    {
        // how to copy base()??
        ...copy extra propertie....
    }
}
您可以使用关键字,该关键字用于访问父类的成员

class B : A 
{
    ... extra properties ...
    public B Copy()
    {
        base.Copy();
        ... copy extra properties ...
    }
}
您可以使用关键字,该关键字用于访问父类的成员

class B : A 
{
    ... extra properties ...
    public B Copy()
    {
        base.Copy();
        ... copy extra properties ...
    }
}

您通常通过受保护的复制构造函数来实现这一点

下面是一个示例程序,它演示了(它使用术语“克隆”而不是“复制”,但效果相同)

我知道你说过你不想克隆,但复制其实是一回事,至少在这种情况下是这样的

无论如何,也许这会给你一些想法。如果你想的话,把所有出现的“克隆”改为“复制”。)

而且,iClonable的使用在这些日子里是不受欢迎的。不过,这显示了一般的方法

注意:这是一个完整的可编译示例,它还使用了一个具有属性的抽象基类,并实现了GetHashCode()-因此看起来相当复杂。因为如果你把每件事都做好,事情会变得复杂

using System;
using System.IO;
using System.Diagnostics;

/*

This code demonstrates a cloning pattern that you can use for class hierarchies.

The abstract base class specifies an abstract Clone() method which must be implemented by all derived classes.
Every class except the abstract base class must have a protected copy constructor. 

This protected copy constructor will:

(1) call the base class' copy constructor, and 
(2) set any new fields introduced in the derived class.

This code also demonstrates an implementation of Equals() and CopyFrom().

*/

namespace CloningPattern
{
    static class Program
    {
        static void Main()
        {
            Derived2 test = new Derived2()
            {
                IntValue = 1,
                StringValue = "s",
                DoubleValue = 2,
                ShortValue = 3
            };

            Derived2 copy = Clone(test);
            Console.WriteLine(copy);
        }

        static Derived2 Clone(AbstractBase item)
        {
            AbstractBase abstractBase = (AbstractBase) item.Clone();
            Derived2 result = abstractBase as Derived2;
            Debug.Assert(result != null);
            return result;
        }
    }

    public abstract class AbstractBase: ICloneable
    {
        // Sample data field.

        public int IntValue { get; set; }

        // Canonical way of providing a Clone() operation
        // (except that this is abstract rather than virtual, since this class
        // is itself abstract).

        public abstract object Clone();

        // Default constructor.

        protected AbstractBase(){}

        // Copy constructor.

        protected AbstractBase(AbstractBase other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            this.copyFrom(other);
        }

        // Copy from another instance over the top of an already existing instance.

        public virtual void CopyFrom(AbstractBase other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            this.copyFrom(other);
        }

        // Equality check.

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (this.GetType() != obj.GetType())
            {
                return false;
            }

            AbstractBase other = (AbstractBase)obj;

            return (this.IntValue == other.IntValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            return this.IntValue.GetHashCode();
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return "IntValue = " + IntValue;
        }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(AbstractBase other)  // 'other' cannot be null, so no check for nullness is made.
        {
            this.IntValue = other.IntValue;
        }
    }

    public abstract class AbstractDerived: AbstractBase
    {
        // Sample data field.

        public short ShortValue{ get; set; }

        // Default constructor.

        protected AbstractDerived(){}

        // Copy constructor.

        protected AbstractDerived(AbstractDerived other): base(other)
        {
            this.copyFrom(other);
        }

        // Copy from another instance over the top of an already existing instance.

        public override void CopyFrom(AbstractBase other)
        {
            base.CopyFrom(other);
            this.copyFrom(other as AbstractDerived);
        }

        // Comparison.

        public override bool Equals(object obj)
        {
            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (!base.Equals(obj))
            {
                return false;
            }

            AbstractDerived other = (AbstractDerived)obj;  // This must succeed because if the types are different, base.Equals() returns false.

            return (this.IntValue == other.IntValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            // "Standard" way of combining hash codes from subfields.

            int hash = 17;

            hash = hash * 23 + base.GetHashCode();
            hash = hash * 23 + this.ShortValue.GetHashCode();

            return hash;
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return base.ToString() + ", ShortValue = " + ShortValue;
        }

        // This abstract class doesn't need to implement Clone() because no instances of it
        // can ever be created, on account of it being abstract and all that.
        // If you COULD, it would look like this (but you can't so this won't compile):

        // public override object Clone()
        // {
        //     return new AbstractDerived(this);
        // }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(AbstractDerived other)  // Other could be null, so check for nullness.
        {
            if (other != null)
            {
                this.ShortValue = other.ShortValue;
            }
        }
    }

    public class Derived1: AbstractDerived
    {
        // Must declare a default constructor.

        public Derived1(){}

        // Sample data field.

        public string StringValue{ get; set; }

        // Implement Clone() by simply using this class' copy constructor.

        public override object Clone()
        {
            return new Derived1(this);
        }

        // Copy from another instance over the top of an already existing instance.

        public override void CopyFrom(AbstractBase other)
        {
            base.CopyFrom(other);
            this.copyFrom(other as Derived1);
        }

        // Equality check.

        public override bool Equals(object obj)
        {
            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (!base.Equals(obj))
            {
                return false;
            }

            Derived1 other = (Derived1)obj;  // This must succeed because if the types are different, base.Equals() returns false.

            return (this.StringValue == other.StringValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            // "Standard" way of combining hash codes from subfields.

            int hash = 17;

            hash = hash * 23 + base.GetHashCode();
            hash = hash * 23 + this.StringValue.GetHashCode();

            return hash;
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return base.ToString() + ", StringValue = " + StringValue;
        }

        // Protected copy constructor. Used to implement Clone().
        // Also called by a derived class' copy constructor.

        protected Derived1(Derived1 other): base(other)
        {
            this.copyFrom(other);
        }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(Derived1 other)  // Other could be null, so check for nullness.
        {
            if (other != null)
            {
                this.StringValue = other.StringValue;
            }
        }
    }

    public class Derived2: Derived1
    {
        // Must declare a default constructor.

        public Derived2(){}

        // Sample data field.

        public double DoubleValue{ get; set; }

        // Implement Clone() by simply using this class' copy constructor.

        public override object Clone()
        {
            return new Derived2(this);
        }

        // Copy from another instance over the top of an already existing instance.

        public override void CopyFrom(AbstractBase other)
        {
            base.CopyFrom(other);
            this.copyFrom(other as Derived2);
        }

        // Equality check.

        public override bool Equals(object obj)
        {
            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (!base.Equals(obj))
            {
                return false;
            }

            Derived2 other = (Derived2)obj;  // This must succeed because if the types are different, base.Equals() returns false.

            return (this.DoubleValue == other.DoubleValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            // "Standard" way of combining hash codes from subfields.

            int hash = 17;

            hash = hash * 23 + base.GetHashCode();
            hash = hash * 23 + this.DoubleValue.GetHashCode();

            return hash;
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return base.ToString() + ", DoubleValue = " + DoubleValue;
        }

        // Protected copy constructor. Used to implement Clone().
        // Also called by a derived class' copy constructor.

        protected Derived2(Derived2 other): base(other)
        {
            // Canonical implementation: use ":base(other)" to copy all
            // the base fields (which recursively applies all the way to the ultimate base)
            // and then explicitly copy any of this class' fields here:

            this.copyFrom(other);
        }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(Derived2 other)  // Other could be null, so check for nullness.
        {
            if (other != null)
            {
                this.DoubleValue = other.DoubleValue;
            }
        }
    }
}

您通常通过受保护的复制构造函数来实现这一点

下面是一个示例程序,它演示了(它使用术语“克隆”而不是“复制”,但效果相同)

我知道你说过你不想克隆,但复制其实是一回事,至少在这种情况下是这样的

无论如何,也许这会给你一些想法。如果你想的话,把所有出现的“克隆”改为“复制”。)

而且,iClonable的使用在这些日子里是不受欢迎的。不过,这显示了一般的方法

注意:这是一个完整的可编译示例,它还使用了一个具有属性的抽象基类,并实现了GetHashCode()-因此看起来相当复杂。因为如果你把每件事都做好,事情会变得复杂

using System;
using System.IO;
using System.Diagnostics;

/*

This code demonstrates a cloning pattern that you can use for class hierarchies.

The abstract base class specifies an abstract Clone() method which must be implemented by all derived classes.
Every class except the abstract base class must have a protected copy constructor. 

This protected copy constructor will:

(1) call the base class' copy constructor, and 
(2) set any new fields introduced in the derived class.

This code also demonstrates an implementation of Equals() and CopyFrom().

*/

namespace CloningPattern
{
    static class Program
    {
        static void Main()
        {
            Derived2 test = new Derived2()
            {
                IntValue = 1,
                StringValue = "s",
                DoubleValue = 2,
                ShortValue = 3
            };

            Derived2 copy = Clone(test);
            Console.WriteLine(copy);
        }

        static Derived2 Clone(AbstractBase item)
        {
            AbstractBase abstractBase = (AbstractBase) item.Clone();
            Derived2 result = abstractBase as Derived2;
            Debug.Assert(result != null);
            return result;
        }
    }

    public abstract class AbstractBase: ICloneable
    {
        // Sample data field.

        public int IntValue { get; set; }

        // Canonical way of providing a Clone() operation
        // (except that this is abstract rather than virtual, since this class
        // is itself abstract).

        public abstract object Clone();

        // Default constructor.

        protected AbstractBase(){}

        // Copy constructor.

        protected AbstractBase(AbstractBase other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            this.copyFrom(other);
        }

        // Copy from another instance over the top of an already existing instance.

        public virtual void CopyFrom(AbstractBase other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            this.copyFrom(other);
        }

        // Equality check.

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (this.GetType() != obj.GetType())
            {
                return false;
            }

            AbstractBase other = (AbstractBase)obj;

            return (this.IntValue == other.IntValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            return this.IntValue.GetHashCode();
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return "IntValue = " + IntValue;
        }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(AbstractBase other)  // 'other' cannot be null, so no check for nullness is made.
        {
            this.IntValue = other.IntValue;
        }
    }

    public abstract class AbstractDerived: AbstractBase
    {
        // Sample data field.

        public short ShortValue{ get; set; }

        // Default constructor.

        protected AbstractDerived(){}

        // Copy constructor.

        protected AbstractDerived(AbstractDerived other): base(other)
        {
            this.copyFrom(other);
        }

        // Copy from another instance over the top of an already existing instance.

        public override void CopyFrom(AbstractBase other)
        {
            base.CopyFrom(other);
            this.copyFrom(other as AbstractDerived);
        }

        // Comparison.

        public override bool Equals(object obj)
        {
            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (!base.Equals(obj))
            {
                return false;
            }

            AbstractDerived other = (AbstractDerived)obj;  // This must succeed because if the types are different, base.Equals() returns false.

            return (this.IntValue == other.IntValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            // "Standard" way of combining hash codes from subfields.

            int hash = 17;

            hash = hash * 23 + base.GetHashCode();
            hash = hash * 23 + this.ShortValue.GetHashCode();

            return hash;
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return base.ToString() + ", ShortValue = " + ShortValue;
        }

        // This abstract class doesn't need to implement Clone() because no instances of it
        // can ever be created, on account of it being abstract and all that.
        // If you COULD, it would look like this (but you can't so this won't compile):

        // public override object Clone()
        // {
        //     return new AbstractDerived(this);
        // }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(AbstractDerived other)  // Other could be null, so check for nullness.
        {
            if (other != null)
            {
                this.ShortValue = other.ShortValue;
            }
        }
    }

    public class Derived1: AbstractDerived
    {
        // Must declare a default constructor.

        public Derived1(){}

        // Sample data field.

        public string StringValue{ get; set; }

        // Implement Clone() by simply using this class' copy constructor.

        public override object Clone()
        {
            return new Derived1(this);
        }

        // Copy from another instance over the top of an already existing instance.

        public override void CopyFrom(AbstractBase other)
        {
            base.CopyFrom(other);
            this.copyFrom(other as Derived1);
        }

        // Equality check.

        public override bool Equals(object obj)
        {
            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (!base.Equals(obj))
            {
                return false;
            }

            Derived1 other = (Derived1)obj;  // This must succeed because if the types are different, base.Equals() returns false.

            return (this.StringValue == other.StringValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            // "Standard" way of combining hash codes from subfields.

            int hash = 17;

            hash = hash * 23 + base.GetHashCode();
            hash = hash * 23 + this.StringValue.GetHashCode();

            return hash;
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return base.ToString() + ", StringValue = " + StringValue;
        }

        // Protected copy constructor. Used to implement Clone().
        // Also called by a derived class' copy constructor.

        protected Derived1(Derived1 other): base(other)
        {
            this.copyFrom(other);
        }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(Derived1 other)  // Other could be null, so check for nullness.
        {
            if (other != null)
            {
                this.StringValue = other.StringValue;
            }
        }
    }

    public class Derived2: Derived1
    {
        // Must declare a default constructor.

        public Derived2(){}

        // Sample data field.

        public double DoubleValue{ get; set; }

        // Implement Clone() by simply using this class' copy constructor.

        public override object Clone()
        {
            return new Derived2(this);
        }

        // Copy from another instance over the top of an already existing instance.

        public override void CopyFrom(AbstractBase other)
        {
            base.CopyFrom(other);
            this.copyFrom(other as Derived2);
        }

        // Equality check.

        public override bool Equals(object obj)
        {
            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (!base.Equals(obj))
            {
                return false;
            }

            Derived2 other = (Derived2)obj;  // This must succeed because if the types are different, base.Equals() returns false.

            return (this.DoubleValue == other.DoubleValue);
        }

        // Get hash code.

        public override int GetHashCode()
        {
            // "Standard" way of combining hash codes from subfields.

            int hash = 17;

            hash = hash * 23 + base.GetHashCode();
            hash = hash * 23 + this.DoubleValue.GetHashCode();

            return hash;
        }

        // ToString() for debug purposes.

        public override string ToString()
        {
            return base.ToString() + ", DoubleValue = " + DoubleValue;
        }

        // Protected copy constructor. Used to implement Clone().
        // Also called by a derived class' copy constructor.

        protected Derived2(Derived2 other): base(other)
        {
            // Canonical implementation: use ":base(other)" to copy all
            // the base fields (which recursively applies all the way to the ultimate base)
            // and then explicitly copy any of this class' fields here:

            this.copyFrom(other);
        }

        // Implement copying fields in a private non-virtual method, called from more than one place.

        private void copyFrom(Derived2 other)  // Other could be null, so check for nullness.
        {
            if (other != null)
            {
                this.DoubleValue = other.DoubleValue;
            }
        }
    }
}

一个常见的解决方案是定义一个从另一个实例复制所有属性的构造函数。然后,派生类复制其类中定义的属性,并调用基类构造函数来复制基类的属性

class A 
{
    // properties

    protected A(A other)
    {
        // copy properties
    }

    public A Clone()
    {
        A clone = CloneCore() as A;
        if (clone == null)
            throw new NotImplementedException("Clone Not Implemented Correctly");
        return clone;
    }

    protected virtual object CloneCore()
    {
        return new A(this);
    }
}

一个常见的解决方案是定义一个从另一个实例复制所有属性的构造函数。然后,派生类复制其类中定义的属性,并调用基类构造函数来复制基类的属性

class A 
{
    // properties

    protected A(A other)
    {
        // copy properties
    }

    public A Clone()
    {
        A clone = CloneCore() as A;
        if (clone == null)
            throw new NotImplementedException("Clone Not Implemented Correctly");
        return clone;
    }

    protected virtual object CloneCore()
    {
        return new A(this);
    }
}

简单回答:你不能

由于
A.Copy()
返回类型
A
,因此不能将其更改为返回A
B

对象上已经有一个方法可以将所有字段复制到新对象中。它被称为
object.MemberwiseClone()
。但是要小心,因为它将执行浅拷贝。(意味着所有引用类型成员都将指向现有对象)

根据我的发现,您通常需要一个深度复制,不幸的是,这意味着您必须在
a
所包含的每个类中编写一个“深度复制”方法

Clone()
方法通常被理解为深度副本。(注释总是有用的)并且,它返回
对象
。如果您想返回
B
,则需要进行强制转换。这并不是一个好办法,因为您无法更改继承方法的签名

还有一件事:定义函数时不要使用
new
关键字。它破坏了多态性,并可能导致难以发现的bug

public class A : IClonable {
   public ReferenceType member1;
   public int member2;

   public object Clone() {
       var clone = this.MemberwiseClone() as A;  //shallow copy
       clone.CloneReferenceMembers();            //deep copy
       return clone;
   }
   public virtual void CloneReferenceMembers(){
      this.member1 = this.member1.Clone();
   }

}

public class B : A {
   public AnotherReferenceType member3;
   public int member4;

    public override void CloneReferenceMembers(){
       base.CloneReferenceMembers();
       this.member3 = this.member3.Clone();
   }
}

简单回答:你不能

由于
A.Copy()
返回类型
A
,因此不能将其更改为返回A
B

对象上已经有一个方法可以将所有字段复制到新对象中。它被称为
object.MemberwiseClone()
。但是要小心,因为它将执行浅拷贝。(意味着所有引用类型成员都将指向现有对象)

根据我的发现,您通常需要一个深度复制,不幸的是,这意味着您必须在
a
所包含的每个类中编写一个“深度复制”方法

Clone()
方法通常被理解为深度副本。(注释总是有用的)并且,它返回
对象
。如果您想返回
B
,则需要进行强制转换。这并不是一个好办法,因为您无法更改继承方法的签名

还有一件事:定义函数时不要使用
new
关键字。它破坏了多态性,并可能导致难以发现的bug

public class A : IClonable {
   public ReferenceType member1;
   public int member2;

   public object Clone() {
       var clone = this.MemberwiseClone() as A;  //shallow copy
       clone.CloneReferenceMembers();            //deep copy
       return clone;
   }
   public virtual void CloneReferenceMembers(){
      this.member1 = this.member1.Clone();
   }

}

public class B : A {
   public AnotherReferenceType member3;
   public int member4;

    public override void CloneReferenceMembers(){
       base.CloneReferenceMembers();
       this.member3 = this.member3.Clone();
   }
}

Base.Copy()?看见我不会把它作为一个答案发布(我不喜欢在答案中推广我自己的网站),但是任何觉得它有用的人都可以免费发布。@cdhowie:Nice blog。这对克隆/复制很有帮助。@MatthewWatson谢谢。dtb的答案很好地利用了受保护的拷贝构造函数,以减少我的博客条目所需的大量样板代码。我现在可能要写一篇后续文章了。Base.Copy()?看见我不会把它作为一个答案发布(我不喜欢在答案中推广我自己的网站),但是任何觉得它有用的人都可以免费发布。@cdhowie:Nice blog。这对克隆/复制很有帮助。@MatthewWatson谢谢。dtb的答案很好地利用了受保护的拷贝构造函数,以减少我的博客条目所需的大量样板代码。我现在可能要写一篇后续文章了。顺便说一句,我删除了我原来的评论,并在意识到我的错误后进行了投票。我经常看到这种模式,只有在公共构造函数中,它总是让我感到不安。我完全忽略了一个事实,即您的构造函数受到保护+1是的,公共复制系数不好,受保护的复制系数正常。这与我的示例所做的类似(但我的示例也使用抽象类,并且显示了实际的属性)