C# 是否有一种通过类的层次结构分配属性的方法?

C# 是否有一种通过类的层次结构分配属性的方法?,c#,overriding,C#,Overriding,请参见以下类的层次结构: Person [age, country, hair color, eyes color..] Adult [job, car..] Man [favorite beer..] Woman [purse..] Child [school, favorite toy] Boy Girl [doll] 每个派生类都有特定的属性:例如,成年人可能有工作,但孩子没有。一个女孩可能有一个最喜欢的娃娃和一个学校的名字。一

请参见以下类的层次结构:

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
并手动设置从
Child
Person
继承的所有属性,而是希望避免这种情况

注意:
Child
成人
Person
是抽象类

注2:所有这些人都有我不想复制的复杂引用,在某些情况下,我只想复制引用的ID,但这应该手动完成,所以我需要对克隆对象进行一些控制

我在
Person
中想到了一个虚拟方法,它在每个子类中都被重写,但由于
Person
无法实例化,我不确定如何实现此行为。
MemberwiseClone()
方法可能就是您正在寻找的:

请注意,您需要手动克隆属于引用类型的类的任何成员,因为上述函数将仅克隆它们的引用,并且生成的男孩克隆成员将引用与这些成员的原始实例相同的实例


如果您的大多数或所有成员都是引用类型,那么iClonable是一个更健壮的解决方案:

不必走浅层/深层克隆的道路(正如Marco指出的那样),您可以使用自己的
克隆功能来实现这一点

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); }
   }

您可以在基类上使用simple,如果您想在上层类中重写,可以使用virtualso

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;
                }
          }
采取3

解决方案1:

我更喜欢的方法是使用ICopyTo。我认为它比其他任何东西都好,因为它强制要有一个适当类型的对象来复制。它还同时进行克隆和复制。易于维护

同时,使用界面也有助于做正确的事情。别忘了打电话给base.CopyTo

而且,我们可以说CopyTo是

公共接口ICopyTo
{
T-CopyTo(T-target);
}
公共抽象类人物:ICopyTo,可克隆
{
公众人士抄送(个人)
{
人。年龄=年龄;
个人。国家=国家;
返回人;
}
公共抽象对象克隆();
公共整数{get;set;}
公共字符串国家{get;set;}
}
公共抽象类成人:Person,ICopyTo,可克隆
{
公共成人复制到(成人)
{
base.CopyTo(这个);
成人车=汽车;
返回成人;
}
公共字符串Car{get;set;}
}
公务舱男:成人,依卡比托,可克隆
{
公共人工复制到(人工=null)
{
if(man==null)
{
人=新人();
}
base.CopyTo(这个);
啤酒=啤酒;
返回人;
}
公共字符串啤酒{get;set;}
公共覆盖对象克隆()
{
返回CopyTo();
}
}
公务舱女性:成人,爱模仿,爱克隆
{
公共女性CopyTo(女性=null)
{
if(woman==null)
{
女人=新女人();
}
base.CopyTo(这个);
女人。钱包=钱包;
回归女性;
}
公共钱包{get;set;}
公共覆盖对象克隆()
{
返回CopyTo();
}
}
公开课考试
{
公共静态void Go()
{
男人1=新男人{Age=10,Beer=“Bud”,Country=“Canada”};
男人2=新男人();
man1.CopyTo(man2);//真实副本
女性1=新女性({Age=32,Country=“USA”,wetch=“Anything”};
Woman woman2=woman1.CopyTo();//克隆
列表成人=新列表();
成人。添加(男性1);
成人。添加(男性2);
成人。添加(女性2);
Person person0=成年人[0]。克隆()为Person;
Person person1=成年人[1]。克隆()为Person;
Person person2=成年人[2]。克隆()为Person;
}
}
解决方案2:(接近解决方案1,但仅在基类上可克隆)

公共接口ICopyTo
{
T-CopyTo(T-target);
}
公共抽象类人物:ICopyTo,可克隆
{
公共虚拟人CopyTo(个人)
{
if(person==null)
{
抛出新ArgumentNullException(“person不能为null”);
}
人。年龄=年龄;
个人。国家=国家;
返回人;
}
公共对象克隆()
{
返回CopyTo(null);
}
公共整数{get;set;}
公共字符串国家{get;set;}
}
公共抽象类成人:Person,ICopyTo,可克隆
{
公共成人复制到(成人)
{
如果(成人==null)
{
抛出新ArgumentNullException(“成人不能为null”);
}
base.CopyTo(这个);
成人车=汽车;
返回成人;
}
公共覆盖个人复制到(个人)
{
将复印件返还给(成人);
}
公共字符串Car{get;set;}
}
公务舱男子:成人,ICopyTo
{
公共人工复制到(人工=null)
{
if(man==null)
{
人=新人();
}
base.CopyTo(这个);
啤酒=啤酒;
返回人;
}
公共覆盖个人复制到(个人)
{
返回(人作为人);
}
公共字符串啤酒{get;set;}
}
公务舱女:成人,ICopyTo
{
公共女性CopyTo(女性=null)
{
if(woman==null)
{
女人=新女人();
}
base.CopyTo(这个);
女人。钱包=钱包;
回归女性;
}
公共覆盖个人复制到(个人)
{
返回(作为女性的人);
}
公共钱包{get;set;}
}
P
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;
    }
}
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;
    }
}
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);
    }
}