2015-11-03 31 views
3

請參閱類的層次結構如下:是否有通過類層次結構分配屬性的方法?

Person [age, country, hair color, eyes color..] 
    Adult [job, car..] 
     Man [favorite beer..] 
     Woman [purse..] 
    Child [school, favorite toy] 
     Boy 
     Girl [doll] 

的每一個派生類的具有特定屬性:例如,成年還可能有工作,但孩子卻沒有。一個女孩可能有一個喜歡的娃娃和一個學校的名字。一個男孩也有一個學校的名字,但他沒有任何喜歡的娃娃。

我想實現克隆Boy(使用完全相同的屬性回退對象Boy)的方法。而不是返回Boy並手動設置從ChildPerson繼承的所有屬性,我想避免這種情況。

注:Child,AdultPerson是抽象類。注2:所有這些人有複雜的引用,我不想複製,在某些情況下,我只是想複製該引用的ID,但應該手動完成,所以我需要一些控制克隆對象。

我想過在每個子類中重寫的Person中的虛擬方法,但因爲Person無法實例化我不知道如何實現此行爲。

+0

對他們實現['ICloneable'](https://msdn.microsoft.com/en-us/library/system.icloneable(v = vs.110).aspx),這樣你的派生類也可以實現它,你只需要在基類上調用克隆來獲得派生類。 –

+0

我可以選擇我想要克隆的屬性嗎?其中一些,如個人身份證號碼應該不同 – Sturm

+0

*「ICloneable接口使您能夠提供一個自定義的實現,創建一個現有對象的副本。」*是的,您可以選擇想要在「克隆「方法。 –

回答

0

不下去的路徑淺/深克隆(馬可指出的),你可以做到這一點,利用自己的Clone功能。

class Person 
{ 
    public Person(Person rhs) // cctor 
    { 
     Age = rhs.Age; 
    } 

    public int Age { get; set; } 

    public abstract Person Clone(); 
} 


    public class Adult : Person 
    { 
     public Adult(Adult rhs) : base(rhs) 
     { 
      JobType = rhs.JobType; 
     } 

     public JobType Job { get; set; } 

     public override Person Clone() { return new Adult(this); } 
    } 
+0

@Sturm,你只需要調用複製構造函數並在每個級別實現'Clone'。 –

+0

仍然無法得到它,因爲我無法調用抽象類的構造函數!所以無法在我的層次結構中通過該級別! – Sturm

0

MemberwiseClone()方法可能是你在找什麼:https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx

被告知你需要克隆是引用類型爲手動上述功能將只克隆他們的引用和類的任何成員導致Boy克隆的成員將爲這些成員引用與原始相同的實例。

如果大多數或所有成員都是引用類型ICloneable是一個更強大的解決方案:https://msdn.microsoft.com/en-us/library/system.icloneable(v=vs.110).aspx

0

你可以使用簡單的基類,如果你想在上層類中重寫,你可以使用虛擬的。

public abstract class Person : ICloneable { 
      public virtual object Clone() { 
       //all upper classes is a Person object 
       person = (Person)Activator.CreateInstance(this.GetType()); 
        person.job = this.job; 
        // ect more properties Lazy or Deep clone 
        person.blah = this.blah; 
        return person; 
       } 
      } 

public abstract class Adult : Person { 
     override object Clone() { 
        Adult adult = (Adult) base.Clone(); 
        adult.job = this.job; 
       } 
      } 
+0

雖然我同意接口的使用,但我不認爲你應該使用Activator.CreateInstance,它創建一個新的對象,而不是克隆。 –

+0

首先,當我們克隆一個對象時,必須創建同一個對象的同一個實例。然後在上面的類中,我們是虛擬的,您可以製作代碼,用於深度克隆或惰性克隆。 – Dimitrios

+0

我明白,但你有它標記'虛擬'而不是'抽象'這意味着派生類有*選項*來實現它,不那麼,只是返回一個新的類的實例,而不是一個克隆,儘管存在「克隆」方法,但它非常混亂。如果你想確保派生類實現它,把它標記爲'abstract',而不是'virtual'(但是你不能有一個方法體)。 –

1

取3 ...

解決方案1:

我的首選方法是使用ICopyTo。我認爲它比其他任何東西都好,因爲它強制要有一個適當類型的對象來複制。它也同時進行克隆和複製。更容易維護。

還使用界面幫助做正確的事情。別忘了打電話給base.CopyTo ...

此外,我們可以說,CopyTo從是Fluent interface

public interface ICopyTo<T> 
{ 
    T CopyTo(T target); 
} 

public abstract class Person : ICopyTo<Person>, ICloneable 
{ 
    public Person CopyTo(Person person) 
    { 
     person.Age = Age; 
     person.Country = Country; 
     return person; 
    } 

    public abstract object Clone(); 

    public int Age { get; set; } 
    public string Country { get; set; } 
} 

public abstract class Adult : Person, ICopyTo<Adult>, ICloneable 
{ 
    public Adult CopyTo(Adult adult) 
    { 
     base.CopyTo(this); 
     adult.Car = Car; 
     return adult; 
    } 

    public string Car { get; set; } 
} 

public class Man : Adult, ICopyTo<Man>, ICloneable 
{ 
    public Man CopyTo(Man man = null) 
    { 
     if (man == null) 
     { 
      man = new Man(); 
     } 
     base.CopyTo(this); 
     man.Beer = Beer; 

     return man; 
    } 


    public string Beer { get; set; } 

    public override object Clone() 
    { 
     return CopyTo(); 
    } 
} 

public class Woman : Adult, ICopyTo<Woman>, ICloneable 
{ 
    public Woman CopyTo(Woman woman = null) 
    { 
     if (woman == null) 
     { 
      woman = new Woman(); 
     } 
     base.CopyTo(this); 
     woman.Purse = Purse; 
     return woman; 
    } 

    public string Purse { get; set; } 

    public override object Clone() 
    { 
     return CopyTo(); 
    } 
} 

public class Test 
{ 
    public static void Go() 
    { 
     Man man1 = new Man() {Age = 10, Beer = "Bud", Country = "Canada"}; 
     Man man2 = new Man(); 
     man1.CopyTo(man2); // Real copy 

     Woman woman1 = new Woman() {Age = 32, Country = "USA", Purse = "Anything"}; 
     Woman woman2 = woman1.CopyTo(); // Cloning 

     List<Person> adults = new List<Person>(); 
     adults.Add(man1); 
     adults.Add(man2); 
     adults.Add(woman2); 

     Person person0 = adults[0].Clone() as Person; 
     Person person1 = adults[1].Clone() as Person; 
     Person person2 = adults[2].Clone() as Person; 
    } 
} 

解決方案2的部分:(只在基部類關閉到溶液1中,但與ICloneable)

public interface ICopyTo<T> 
{ 
    T CopyTo(T target); 
} 

public abstract class Person : ICopyTo<Person>, ICloneable 
{ 
    public virtual Person CopyTo(Person person) 
    { 
     if (person == null) 
     { 
      throw new ArgumentNullException("person can't be null"); 
     } 

     person.Age = Age; 
     person.Country = Country; 
     return person; 
    } 

    public object Clone() 
    { 
     return CopyTo(null); 
    } 

    public int Age { get; set; } 
    public string Country { get; set; } 
} 

public abstract class Adult : Person, ICopyTo<Adult>, ICloneable 
{ 
    public Adult CopyTo(Adult adult) 
    { 
     if (adult == null) 
     { 
      throw new ArgumentNullException("adult can't be null"); 
     } 

     base.CopyTo(this); 
     adult.Car = Car; 
     return adult; 
    } 

    public override Person CopyTo(Person person) 
    { 
     return CopyTo(person as Adult); 
    } 

    public string Car { get; set; } 
} 

public class Man : Adult, ICopyTo<Man> 
{ 
    public Man CopyTo(Man man = null) 
    { 
     if (man == null) 
     { 
      man = new Man(); 
     } 
     base.CopyTo(this); 
     man.Beer = Beer; 

     return man; 
    } 

    public override Person CopyTo(Person person) 
    { 
     return CopyTo(person as Man); 
    } 

    public string Beer { get; set; } 
} 

public class Woman : Adult, ICopyTo<Woman> 
{ 
    public Woman CopyTo(Woman woman = null) 
    { 
     if (woman == null) 
     { 
      woman = new Woman(); 
     } 
     base.CopyTo(this); 
     woman.Purse = Purse; 
     return woman; 
    } 

    public override Person CopyTo(Person person) 
    { 
     return CopyTo(person as Woman); 
    } 

    public string Purse { get; set; } 
} 

public class Test 
{ 
    public static void Go() 
    { 
     Man man1 = new Man() {Age = 10, Beer = "Bud", Country = "Canada"}; 
     Man man2 = new Man(); 
     man1.CopyTo(man2); // Real copy 

     Woman woman1 = new Woman() {Age = 32, Country = "USA", Purse = "Anything"}; 
     Woman woman2 = woman1.CopyTo(); // Cloning 

     List<Person> adults = new List<Person>(); 
     adults.Add(man1); 
     adults.Add(man2); 
     adults.Add(woman2); 

     Person person0 = adults[0].Clone() as Person; 
     Person person1 = adults[1].Clone() as Person; 
     Person person2 = adults[2].Clone() as Person; 
    } 
} 

解決方案3:

public static T Clone<T>(T source) 
{ 
    if (!typeof(T).IsSerializable) 
    { 
     throw new ArgumentException("The type must be serializable.", "source"); 
    } 

    // Don't serialize a null object, simply return the default for that object 
    if (Object.ReferenceEquals(source, null)) 
    { 
     return default(T); 
    } 

    IFormatter formatter = new BinaryFormatter(); 
    Stream stream = new MemoryStream(); 
    using (stream) 
    { 
     formatter.Serialize(stream, source); 
     stream.Seek(0, SeekOrigin.Begin); 
     return (T)formatter.Deserialize(stream); 
    } 
} 
+0

傑出的例子。很高興看到同樣的問題有很多方法。這是我最喜歡的(1):) – Sturm

+0

在你更新的答案中,現在使用ICloneable接口。即使基類已經實現了該接口,它也會繼承每個子類。這是爲什麼? – Sturm

+0

我同意這聽起來沒有必要......我期待着看看我是否可以僅在基礎上使用實現。我在幾分鐘內回來... –

相關問題