从父对象创建子对象实例的最佳方法

我正在从父对象创建一个子对象。 所以场景是我有一个对象和一个子对象,它为我想要搜索的场景添加了一个距离属性。 我选择使用inheritance,因为我的UI与搜索对象或对象列表等效地工作,而不是位置搜索的结果。 所以在这种情况下,inheritance似乎是一个明智的选择。

目前我需要从MyObjectSearch的一个实例生成一个新对象MyObject 。 目前我通过逐个设置属性手动在构造函数中执行此操作。 我可以使用reflection,但这会很慢。 有没有更好的方法来实现这种对象增强?

希望下面的代码说明了这个场景。

 public class MyObject { // Some properties and a location. } public class MyObjectSearch : MyObject { public double Distance { get; set; } public MyObjectSearch(MyObject obj) { base.Prop1 = obj.Prop1; base.Prop2 = obj.Prop2; } } 

我的搜索function:

 public List DoSearch(Location loc) { var myObjectSearchList = new List(); foreach (var object in myObjectList) { var distance = getDistance(); var myObjectSearch = new MyObjectSearch(object); myObjectSearch.Distance = distance; myObjectSearchList.add(myObjectSearch); } return myObjectSearchList; 

}

基类需要定义一个复制构造函数:

 public class MyObject { protected MyObject(MyObject other) { this.Prop1=other.Prop1; this.Prop2=other.Prop2; } public object Prop1 { get; set; } public object Prop2 { get; set; } } public class MyObjectSearch : MyObject { public double Distance { get; set; } public MyObjectSearch(MyObject obj) : base(obj) { this.Distance=0; } public MyObjectSearch(MyObjectSearch other) : base(other) { this.Distance=other.Distance; } } 

这样,基类就可以为所有派生类处理属性设置。

不幸的是,没有简单的方法可以做到这一点。 正如你所说,你要么必须使用reflection,要么创建一个“克隆”方法,使用父对象作为输入生成一个新的子对象,如下所示:

 public class MyObjectSearch : MyObject { // Other code public static MyObjectSearch CloneFromMyObject(MyObject obj) { var newObj = new MyObjectSearch(); // Copy properties here obj.Prop1 = newObj.Prop1; return newObj; } } 

无论如何,你要么最终要编写reflection代码(这很慢),要么手工编写每个属性。 这完全取决于您是否需要可维护性(reflection)或速度(手动属性复制)。

对于基础对象来说,看起来很自然,它的构造函数具有其属性的参数:

 public class MyObject { public MyObject(prop1, prop2, ...) { this.Prop1 = prop1; this.Prop2 = prop2; } } 

那么,在您的后代对象中,您可以:

 public MyObjectSearch(MyObject obj) :base(obj.Prop1, obj.Prop2) 

这减少了与分配相关的重复。 您可以使用reflection来自动复制所有属性,但这种方式似乎更具可读性。

另请注意,如果您的类具有如此多的属性,以至于您正在考虑自动化复制属性,那么它们可能违反单一责任原则 ,您应该考虑更改您的设计。

一般的解决方案是将其序列化为json并返回。 在json-string中没有关于序列化它的类名的信息。 大多数人在javascript中这样做。

如你所见,它适用于pocco对象,但我不保证它适用于所有复杂的情况。 但是当匹配属性时,它会为非inheritance类执行事件。

 using Newtonsoft.Json; namespace CastParentToChild { public class Program { public static void Main(string[] args) { var p = new parent(); pa=111; var s = JsonConvert.SerializeObject(p); var c1 = JsonConvert.DeserializeObject(s); var c2 = JsonConvert.DeserializeObject(s); var foreigner = JsonConvert.DeserializeObject(s); bool allWorks = pa == c1.a && pa == c2.a && pa == foreigner.a; //Your code goes here Console.WriteLine("Is convertable: "+allWorks + c2.b); } } public class parent{ public int a; } public class child1 : parent{ public int b=12345; } public class child2 : child1{ } public class NoFamily{ public int a; public int b = 99999; } // Is not Deserializeable because // Error 'NoFamily2' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type 'NoFamily2' could be found (are you missing a using directive or an assembly reference?) public class NoFamily2{ public int b; } } 

您可以使用reflection来复制属性。

 public class ChildClass : ParentClass { public ChildClass(ParentClass ch) { foreach (var prop in ch.GetType().GetProperties()) { this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(ch, null), null); } } } 

有库来处理这个问题; 但是如果你只是想在一些地方快速实现,我肯定会按照之前的建议选择“复制构造函数”。

没有提到的一个有趣的观点是,如果一个对象是一个子类,那么它可以从父级内部访问子级的私有变量!

因此,在父级上添加CloneIntoChild方法。 在我的例子中:

  • Order是父类
  • OrderSnapshot是子类
  • _bestPrice_bestPrice上的非_bestPrice私有成员。 但Order可以为OrderSnapshot设置它。

例:

 public OrderSnapshot CloneIntoChild() { OrderSnapshot sn = new OrderSnapshot() { _bestPrice = this._bestPrice, _closed = this._closed, _opened = this._opened, _state = this._state }; return sn; } 

注意:必须在构造函数中设置只读成员变量,因此您必须使用子构造函数来设置这些…

虽然我不喜欢“大小调整”,但我对分析快照使用这种方法很多……

如果浅拷贝就足够了,可以使用MemberwiseClone方法 。

例:

 MyObject shallowClone = (MyObject)original.MemberwiseClone(); 

如果您需要深层副本,可以像这样序列化/反序列化: https : //stackoverflow.com/a/78612/1105687

一个例子(假设您按照该答案中的建议编写了一个扩展方法,并将其称为DeepClone)

 MyObject deepClone = original.DeepClone();