有没有一种方法可以通过 类 的层次结构来分配属性?
Is there a way of assigning properties through a hierarchy of classes?
请参阅类的以下层次结构:
Person [age, country, hair color, eyes color..]
Adult [job, car..]
Man [favorite beer..]
Woman [purse..]
Child [school, favorite toy]
Boy
Girl [doll]
每个派生的 类 都有特定的属性:例如,成年人可能有工作,但 child 没有。一个女孩可能有一个最喜欢的洋娃娃和一个学校的名字。一个男孩也有学校名字,但他没有喜欢的娃娃。
我想实现一个克隆 Boy
的方法(返回具有完全相同属性的 Boy
object)。我不想返回 Boy
并手动设置从 Child
和 Person
继承的所有属性,而是想避免这种情况。
注意:Child
、Adult
和Person
是抽象的类。
注意2:所有这些人都有我不想复制的复杂引用,在某些情况下我只想复制那些引用的ID,但这应该手动完成,所以我需要一些控制克隆 objects.
我想到了 Person
中的一个虚方法,它在每个子类中都被重写了,但是由于 Person
无法实例化,我不确定如何实现这种行为。
MemberwiseClone()
方法可能就是您要找的方法:https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx
请注意,您需要手动克隆 class 的所有引用类型成员,因为上述函数只会克隆它们的引用,而生成的 Boy 克隆成员将引用与那些成员的原创。
如果您的大部分或所有成员都是引用类型,ICloneable 是更可靠的解决方案:https://msdn.microsoft.com/en-us/library/system.icloneable(v=vs.110).aspx
无需沿着路径 shallow/deep 克隆(如 Marco 指出的那样),您可以使用自己的 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); }
}
您可以在基础 class 上使用简单的 class,如果您想在上层 classes 中覆盖,您可以使用虚拟的。
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 是 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,但仅在基础 class 处使用 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);
}
}
请参阅类的以下层次结构:
Person [age, country, hair color, eyes color..]
Adult [job, car..]
Man [favorite beer..]
Woman [purse..]
Child [school, favorite toy]
Boy
Girl [doll]
每个派生的 类 都有特定的属性:例如,成年人可能有工作,但 child 没有。一个女孩可能有一个最喜欢的洋娃娃和一个学校的名字。一个男孩也有学校名字,但他没有喜欢的娃娃。
我想实现一个克隆 Boy
的方法(返回具有完全相同属性的 Boy
object)。我不想返回 Boy
并手动设置从 Child
和 Person
继承的所有属性,而是想避免这种情况。
注意:Child
、Adult
和Person
是抽象的类。
注意2:所有这些人都有我不想复制的复杂引用,在某些情况下我只想复制那些引用的ID,但这应该手动完成,所以我需要一些控制克隆 objects.
我想到了 Person
中的一个虚方法,它在每个子类中都被重写了,但是由于 Person
无法实例化,我不确定如何实现这种行为。
MemberwiseClone()
方法可能就是您要找的方法:https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx
请注意,您需要手动克隆 class 的所有引用类型成员,因为上述函数只会克隆它们的引用,而生成的 Boy 克隆成员将引用与那些成员的原创。
如果您的大部分或所有成员都是引用类型,ICloneable 是更可靠的解决方案:https://msdn.microsoft.com/en-us/library/system.icloneable(v=vs.110).aspx
无需沿着路径 shallow/deep 克隆(如 Marco 指出的那样),您可以使用自己的 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); }
}
您可以在基础 class 上使用简单的 class,如果您想在上层 classes 中覆盖,您可以使用虚拟的。
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 是 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,但仅在基础 class 处使用 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);
}
}