2013-03-22 53 views
0

我有一個B類派生自另一個類A.A類實現了一個Copy方法。如何在使用A.Copy()的B類中實現Copy方法?如何在創建新實例時使用基類中的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.... 
    } 
} 
+0

Base.Copy()?請參閱http://msdn.microsoft.com/en-us/library/hfw7t1ce%28v=vs.71%29.aspx – David 2013-03-22 15:47:45

+1

[我的博客回答了這個問題](http://blog.chrishowie.com/2013/01/22 /對象複製功能於C /)。我不會將它作爲答案發布(我不喜歡在答案中宣傳自己的網站),但其他任何認爲有用的網站都是免費的。 – cdhowie 2013-03-22 15:48:40

+0

@cdhowie:好博客。這很好地克隆/複製。 – 2013-03-22 15:54:47

回答

0

您可以使用base關鍵字,該關鍵字用於訪問父類的成員。

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

不認爲這實際上將複製任何東西到B級... – paul 2013-03-25 06:14:43

1

您經常通過受保護的拷貝構造函數來實現此操作。

下面是這表明(它使用的術語「克隆」,而不是「複製」的示例程序,但效果是一樣的。

我知道你說你不想克隆,但複製是真的。同樣的事情,在這種情況下,至少

不管怎樣,這也許會給你一些想法更改「克隆」,「複製」,如果你想......所有出現的。)

此外,這些日子,ICloneable的使用受到了詬病。不過,這顯示了一般方法。

注意:這是一個完整的可編譯示例,它也使用具有屬性的抽象基類,並實現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; 
      } 
     } 
    } 
} 
3

常見的解決方案是定義一個構造函數,複製從另一個實例的所有屬性。派生類然後複製在他們的類中定義的屬性,並調用基礎構造函數來複制基類的屬性。

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 B : A 
{ 
    // one extra property 

    protected B(B other) : base(other) 
    { 
     // copy extra property 
    } 

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

    protected override object CloneCore() 
    { 
     return new B(this); 
    } 
} 
+0

BTW,我刪除了原來的評論和upvoted一旦我意識到自己的錯誤。我見過這種模式很多,只有使用公共構造函數,並且總是給我帶來困擾。我完全錯過了你的構造函數受到保護的事實。 +1 – cdhowie 2013-03-22 15:56:44

+0

是的,公共副本錯誤,受保護的副本可以。這是類似於我的例子是做(但該礦還使用抽象類,並呈現出正被複制的實際性能,所以它看起來要複雜得多!) – 2013-03-22 16:00:15

+0

嗯......我的解決方案可能是有點太簡單了。如果你在'A'變量中有一個'B'實例並且調用'Copy',那麼你得到'A'而不是'B'。我會解決這個問題... – dtb 2013-03-22 16:01:56

0

簡短的回答:不能。

由於A.Copy()返回類型A它不能被更改爲返回B

對象上已經有一個方法將所有字段複製到一個新對象中。它被稱爲object.MemberwiseClone()。不過要小心,因爲它會執行淺拷貝。 (意味着所有引用類型成員將指向現有對象)。

據我發現,你通常需要一個深拷貝,遺憾的是這意味着你將不得不在每可以通過A包含寫一個「深拷貝」的方法。

A Clone()方法通常被理解爲深層複製。 (意見總是有幫助)並且,它返回object。如果你想要B回來,這將需要演員陣容。由於您無法更改繼承方法的簽名,因此沒有真正的解決方法。

還有一件事:定義函數時不要使用new關鍵字。它打破了多態性,並可能導致難以發現的錯誤。

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(); 
    } 
} 
相關問題