11

OK、私たちは Newtonsoft の JSON.NET 製品を使用しています。これは私がとても気に入っています。ただし、大まかに次のような階層的な場所の単純なクラス構造があります...

public class Location
{
    public string Name{ get; set; }
    public LocationList Locations{ get; set; }
}

// Note: LocationList is simply a subclass of a List<T>
// which then adds an IsExpanded property for use by the UI.
public class LocationList : List<Location>
{
    public bool IsExpanded{ get; set; }
}

public class RootViewModel
{
    public LocationList RootLocations{ get; set; }
}

...そして、それらを JSON にシリアル化すると、LocationList クラスの IsExpanded プロパティが除外されることを除いて、すべてうまく機能します。リストの内容のみがシリアル化されます。

今、私が思い描いているのは良いフォーマットです。LocationListのサブクラスではなく、代わりに の型List<Location>と呼ばれるプロパティを持つ単なる通常のオブジェクトであるかのように、本質的に同じことです。ItemsList<Location>

{
  "Locations":
  {
    "IsExpanded": true,
    "Items": [
      {
        "Name": "Main Residence",
        "Locations":
        {
          "IsExpanded": true,
          "Items": [
            {
              "Name": "First Floor",
              "Locations":
              {
                "IsExpanded": false,
                "Items": [
                  {
                    "Name": "Livingroom"
                  },
                  {
                    "Name": "Dining Room"
                  },
                  {
                    "Name": "Kitchen"
                  }
                ]
            },
            {
              "Name": "Second Floor",
              "Locations":
              {
                "IsExpanded": false,
                "Items": [
                  {
                    "Name": "Master Bedroom"
                  },
                  {
                    "Name": "Guest Bedroom"
                  }
                ]
            },
            {
              "Name": "Basement"
            }
          ]
        }
      }
    ]
  }
}

また、Newtonsoft の製品が拡張可能であることも理解しています。なぜなら、特定のデータ型に対して独自のカスタム シリアライザーを作成する方法について具体的に述べているからです。ただし、これを行う方法に関する適切なコード例はありません。

私たち (SO コミュニティ) がこれを理解できれば、技術的に上記の形式を使用して、リスト (またはその派生物/類似オブジェクト) の任意のサブクラスをシリアル化できるはずですItems。がらくたとして紛らわしいので、そもそも設計が貧弱である必要があります!) おそらく、Newtonsoft にそのようなものをシリアライザでネイティブにロールさせることさえできます!

つまり、シリアライザー/デシリアライザーをカスタマイズして、このオブジェクトを別の方法で処理する方法を知っている人はいますか?

M

4

3 に答える 3

2

通常、私がこのようなものと戦っていることに気付くと、別のアプローチを検討する必要があると言われます. この場合、代替手段として次のビュー モデル構造をお勧めします。

public class Location
{
    public bool IsExpanded { get; set; }
    public string Name { get; set; }
    public List<Location> Locations { get; set; }
}

public class ViewModel
{
    public List<Location> RootLocations { get; set; }
}
于 2011-05-03T01:12:17.100 に答える
1

わかりました...これが私が思いついたものです。独自の JsonConverter を作成する必要がありました。私は基本的にそれを使用して、永続化したいプロパティを構造化したインライン JObject を作成し、それを永続化します。それを読み返すときは、逆のことをします。

ただし、欠点は、リフレクションなどを使用しないため、これは、プロパティごとに手動でコーディングする必要があったこの特定のタイプに対してのみ機能することです (この場合は 2 つしかないので、それで十分です!)また、手動で再エミュレートする必要がある DefaultValues 処理も利用しません。つまり、属性は、よく考えないと基本的に無視されます。それでも、これは機能します。完全?いいえ、でもねえ... めったにありません!

もちろん、コメントは大歓迎です。

public class LocationListJsonConverter : JsonConverter
{
    public override bool CanConvert(System.Type objectType)
    {
        return objectType == typeof(LocationList);
    }

    public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)
    {
        var locationList = (existingValue as LocationList) ?? new LocationList();
        var jLocationList = JObject.ReadFrom(reader);

        locationList.IsExpanded = (bool)(jLocationList["IsExpanded"] ?? false);

        var jLocations = jLocationList["_Items"];
        if(jLocations != null)
        {
            foreach(var jLocation in jLocations)
            {
                var location = serializer.Deserialize<Location>(new JTokenReader(jLocation));
                locationList.Add(location);
            }
        }

        return locationList;

    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var locationList = value as LocationList;

        JObject jLocationList = new JObject();

        if(locationList.IsExpanded)
            jLocationList.Add("IsExpanded", true);

        if(locationList.Count > 0)
        {
            var jLocations = new JArray();

            foreach(var location in locationList)
            {
                jLocations.Add(JObject.FromObject(location, serializer));
            }

            jLocationList.Add("_Items", jLocations);

        }

        jLocationList.WriteTo(writer);

    }

}
于 2011-05-04T20:18:46.833 に答える