2017-03-10 10 views
3

リストから派生した子クラスを持つ再帰クラス(ツリー階層)、JSON.NETでの逆シリアル化から生成された子クラス自体があります。逆シリアル化で値を代入する代入リストの代入

TLDRのバージョンは、JSON.NETの$ ref変数を使用せずに、このクラスの各レベルで、親から子供の変数にデータを設定したいというものです(クッキーに格納するときにスペースを節約します)。

昨日私の質問に従った人にとっては、これは重複しているように見えるかもしれませんが、そうではありません。それは同じコードですが、古い質問はJSONのsetterを中心に解き放たれず(解決されました)、その答えが(もっと適切に言われて)この質問をもたらしました。

最初の呼び出しは次のようになります。

呼び出す
_Items = Cookies.Instance.GetJObject<CartItems>(COOKIE, jsonSetting); 

public T GetJObject<T>(string cookieName, JsonSerializerSettings jset = null) 
    { 
     string cookieContent = Get(cookieName); 
     return JsonConvert.DeserializeObject<T>(cookieContent, jset); 
    } 

を次のようにカスタムコンバータクラスは次のとおりです。

public class JsonCartConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(CartItem).IsAssignableFrom(objectType); 
    } 

    public override bool CanWrite 
    { 
     get 
     { 
      return false; 
     } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject obj = JObject.Load(reader); 

     var type = obj["t"] != null ? (CARTITEMTYPE)obj["t"].Value<int>() : CARTITEMTYPE.GENERIC; 
     var item = CartItems.NewByType(type); 
     serializer.Populate(obj.CreateReader(), item); 
     return item; 
    } 


    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 

    } 
} 

次のように結果のJSONは次のとおりです。

[{"t":1,"i":1,"n":4,"r":false,"c":[{"t":5,"i":2,"n":4,"r":false,"c":[]}]},{"t":1,"i":3,"n":4,"r":false,"c":[{"t":5,"i":4,"n":4,"r":false,"c":[{"t":4,"i":6,"n":14,"r":false,"c":[]}]},{"t":1,"i":5,"n":15,"r":false,"c":[]}]}] 

そして、私は何をしようとしています、このようになります

public class CartItems : List<CartItem>{ 

public new CartItem Add(CartItem item) 
    { 
     item.Parent = this; 
     base.Add(item); 
     return item; 
    } 

だから、問題は、我々は、デシリアライゼーションを移入するためにリストから標準の追加/挿入メソッドを呼び出していないことを確立したことであることリスト。私たちはリフレクションを通してリストを作成していることを知っていますが、どうですか?挿入時に、子クラスの親クラスへの代入を傍受して、親クラス(つまりchild.Parent = this)の子クラスの変数に割り当てることはできますか?

私はJSON.NETソースで、それをポピュレートするために使用しているコレクション内のメソッドを見つけることを試みました(リフレクションであっても、メソッド呼び出しを呼び出して追加する必要があります)。それ以外の場合は...

CartItems items = new CartItems() { new GenericItem() { }, new GenericItem() { } }; 

編集:CartItemsはリストから派生したクラスです。これには、CartItemの複数のインスタンスが設定されます。

答えて

1

あなたの問題は、しかし、List<T>は、関連する方法のいずれも、この方法でサブクラス化するように設計されていない、アイテムが追加され、リストから削除されると、親/子関係を維持するためにList<T>をサブクラス化しようとして仮想されているということです。代わりにpublic new CartItem Add(CartItem item)Add()メソッドを隠していますが、Json.NETがこの置換メソッドを呼び出すわけではないことが判明しました。

代わりに、この目的のために明示的に設計されたCollection<T>を使用する必要があります。 docsから:

Collection<T>クラスが追加と削除項目を、コレクションをクリアしたり、既存の項目の値を設定する際に、その動作をカスタマイズするために使用することができる保護されたメソッドを提供します。CartItemCartItems両方がParent性質を持っていることを

public class CartItems : Collection<CartItem> 
{ 
    public CartItems() : base() { } 

    public CartItems(CartItem parent) : this() 
    { 
     this.Parent = parent; 
    } 

    public CartItem Parent { get; private set; } 

    protected override void RemoveItem(int index) 
    { 
     CartItem oldItem = null; 
     if (index >= 0 && index < Count) 
     { 
      oldItem = this[index]; 
     } 

     base.RemoveItem(index); 
    } 

    protected override void InsertItem(int index, CartItem item) 
    { 
     base.InsertItem(index, item); 
     if (item != null) 
      item.Parent = this; 
    } 

    protected override void SetItem(int index, CartItem item) 
    { 
     CartItem oldItem = null; 
     if (index >= 0 && index < Count) 
     { 
      oldItem = this[index]; 
     } 

     base.SetItem(index, item); 

     if (oldItem != null) 
      oldItem.Parent = null; 

     if (item != null) 
      item.Parent = this; 
    } 

    protected override void ClearItems() 
    { 
     foreach (var item in this) 
      if (item != null) 
       item.Parent = null; 
     base.ClearItems(); 
    } 
} 

public class CartItem 
{ 
    public CartItem() 
    { 
     this.Children = new CartItems(this); 
    } 

    public int t { get; set; } 
    public int i { get; set; } 
    public int n { get; set; } 
    public bool r { get; set; } 

    [JsonProperty("c")] 
    public CartItems Children { get; private set; } 

    [JsonIgnore] 
    public CartItems Parent { get; set; } 
} 

お知らせ:

このように、あなたのオブジェクトモデルは、以下のようになるはずです。 CartItems.Parentがそのコンストラクタに割り当てられます。 CartItem.Parentは、オーバーライドされたInsertItem,SetItemおよびRemoveItemメソッドによって割り当てられます。

サンプルfiddle

Collection<T> versus List<T> what should you use on your interfaces?も参照してください。

+0

これは本当に美しいものです。私は、壁に向かって頭を打って、これを一番長い間把握しようとしています。もし私がそれを100倍アップビューすることができたら、私はそうするだろう。なぜ私はこれを思い付かなかったのか、それとも私が持っていたのか分かりません。私はすべての間違った角度から攻撃してきました。 – dudeinco

+0

@dudeinco - 必要ならば 'ObservableCollection 'から 'CartItems'を継承させることもでき、上書きはそのままコンパイルして動作します。 – dbc

+0

当初、私はそれについて実際に考えていましたが、そうするかもしれませんが、私は実装上の印を逃していました...もう一度感謝します。 – dudeinco