親オブジェクトから子オブジェクトを作成しています。つまり、シナリオには、オブジェクトと、検索したいシナリオの距離プロパティを追加する子オブジェクトがあります。 UIは検索オブジェクトまたは場所検索の結果ではなくオブジェクトのリストのいずれかと同等に機能するため、継承を使用することを選択しました。したがって、この場合、継承は賢明な選択のようです。
現在のように、MyObjectSearch
のインスタンスから新しいオブジェクトMyObject
を生成する必要があります。現在は、プロパティを1つずつ設定することで、コンストラクタでこれを手動で行っています。リフレクションを使用できますが、これは遅くなります。この種のオブジェクト拡張を実現するより良い方法はありますか?
うまくいけば、以下の私のコードはシナリオを示しています。
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;
}
}
そして私の検索機能:
public List<MyObjectSearch> DoSearch(Location loc) {
var myObjectSearchList = new List<MyObjectSearch>();
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;
}
}
このようにして、プロパティの設定は、基本クラスによってすべての派生クラスに対して処理されます。
リフレクションを使用してプロパティをコピーできます。
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);
}
}
}
残念ながら、これを行う簡単な方法はありません。言ったように、リフレクションを使用するか、次のように親オブジェクトを入力として使用して新しい子オブジェクトを生成する「Clone」メソッドを作成する必要があります。
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;
}
}
いずれにしても、リフレクションコード(遅い)を書くか、各プロパティを手動で書き出すことになります。それはすべて、保守性(反映)または速度(手動プロパティコピー)が必要かどうかによって異なります。
一般的な解決策は、それをjsonにシリアライズして戻すことです。 json-stringには、シリアル化元のクラス名に関する情報はありません。ほとんどの人はこれをJavaScriptで行います。
ご覧のとおり、それはpoccoオブジェクトでうまく機能しますが、すべての複雑なケースで機能することを保証しません。ただし、プロパティが一致すると、継承されていないクラスのイベントが発生します。
using Newtonsoft.Json;
namespace CastParentToChild
{
public class Program
{
public static void Main(string[] args)
{
var p = new parent();
p.a=111;
var s = JsonConvert.SerializeObject(p);
var c1 = JsonConvert.DeserializeObject<child1>(s);
var c2 = JsonConvert.DeserializeObject<child2>(s);
var foreigner = JsonConvert.DeserializeObject<NoFamily>(s);
bool allWorks = p.a == c1.a && p.a == c2.a && p.a == 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;
}
}
基本オブジェクトがそのプロパティのパラメータを持つコンストラクタを持つのは自然なことのようです:
public class MyObject
{
public MyObject(prop1, prop2, ...)
{
this.Prop1 = prop1;
this.Prop2 = prop2;
}
}
それで、あなたの子孫オブジェクトであなたは持つことができます:
public MyObjectSearch(MyObject obj)
:base(obj.Prop1, obj.Prop2)
これにより、割り当てに関連する重複が削減されます。リフレクションを使用してすべてのプロパティを自動的にコピーすることもできますが、この方が読みやすくなります。
また、クラスに多くのプロパティがあり、プロパティのコピーの自動化を検討している場合、それらは 単一の責任の原則 に違反する可能性が高く、設計の変更を検討する必要があることにも注意してください。 。
これを処理するライブラリがあります。ただし、いくつかの場所で簡単に実装したい場合は、以前に提案した「コピーコンストラクター」を必ず使用します。
言及されていない興味深い点の1つは、オブジェクトがサブクラスの場合、親の内部から子のプライベート変数にアクセスできることです。
したがって、親にCloneIntoChild
メソッドを追加します。私の例では:
Order
は親クラスですOrderSnapshot
は子クラスです_bestPrice
はOrder
の非読み取り専用プライベートメンバーです。ただし、Order
はOrderSnapshot
に設定できます。例:
public OrderSnapshot CloneIntoChild()
{
OrderSnapshot sn = new OrderSnapshot()
{
_bestPrice = this._bestPrice,
_closed = this._closed,
_opened = this._opened,
_state = this._state
};
return sn;
}
注:読み取り専用メンバー変数はコンストラクターで設定する必要があるため、これらを設定するには子コンストラクターを使用する必要があります...
私は一般的に「アップサイジング」は好きではありませんが、この方法は分析スナップショットによく使用します...