簡體   English   中英

JSON 到 C#,反序列化對象或數組的屬性

[英]JSON to C#, deserialize property that is either object or array

我在處理來自我在應用程序中使用的 api 的 JSON 數據時遇到問題。 問題是 JSON 包含一些屬性,當有一個項目時它們是一個對象,當有更多項目時變成一個數組。 所以這是一個這樣的結構:

[
  {
     "MyObj": {
            "Foo": "Bar"
        }
  }, 
  {
     "MyObj": [
            {
                "Foo": "Bar1"
            }, 
            {
                "Foo": "Bar2"
            }
        ]
    }
]

我嘗試了幾個 JSON 到 C# 轉換器,其中一些生成對象類型的屬性,quicktype.io 轉換器生成這個:

public class Example
    {
        [JsonProperty("MyObj")]
        public MyObjUnion MyObj { get; set; }
    }

    public partial class MyObjElement
    {
        [JsonProperty("Foo")]
        public string Foo { get; set; }
    }

    public struct MyObjUnion
    {
        public MyObjElement MyObjElement;
        public MyObjElement[] MyObjElementArray;

        public static implicit operator MyObjUnion(MyObjElement MyObjElement) => new MyObjUnion { MyObjElement = MyObjElement };
        public static implicit operator MyObjUnion(MyObjElement[] MyObjElementArray) => new MyObjUnion { MyObjElementArray = MyObjElementArray };
    }

 internal class MyObjUnionConverter : JsonConverter
    {
        public override bool CanConvert(Type t) => t == typeof(MyObjUnion) || t == typeof(MyObjUnion?);

        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
        {
            switch (reader.TokenType)
            {
                case JsonToken.StartObject:
                    var objectValue = serializer.Deserialize<MyObjElement>(reader);
                    return new MyObjUnion { MyObjElement = objectValue };
                case JsonToken.StartArray:
                    var arrayValue = serializer.Deserialize<MyObjElement[]>(reader);
                    return new MyObjUnion { MyObjElementArray = arrayValue };
            }
            throw new Exception("Cannot unmarshal type MyObjUnion");
        }

        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
        {
            var value = (MyObjUnion)untypedValue;
            if (value.MyObjElementArray != null)
            {
                serializer.Serialize(writer, value.MyObjElementArray);
                return;
            }
            if (value.MyObjElement != null)
            {
                serializer.Serialize(writer, value.MyObjElement);
                return;
            }
            throw new Exception("Cannot marshal type MyObjUnion");
        }

        public static readonly MyObjUnionConverter Singleton = new MyObjUnionConverter();
    }

盡管這確實可以正常工作,但它仍然有點麻煩,因為要獲取數據,您始終需要檢查它是否在MyObjElementMyObjElementArray類中。 所以問題是是否有其他更優雅的方法來解決這個問題。 (除了更改 API 輸出,這不是我的)

如果您事先知道數據結構,我將為 Json 文件創建一個自定義數據模型,然后像這樣反序列化它:

            CurrencyExchangeRates deserialisedData = JsonConvert.DeserializeObject<CurrencyExchangeRates>(savedData);

            foreach (CurrentRate value in deserialisedData.ExchangeRates)
            {
                rate.ExchangeRates.Add(new CurrentRate { Rate = value.Rate, Timestamp = value.Timestamp });
            }

這就是我在應用程序中這樣做的方式。 希望這有所幫助。

您可以根據對象的類型檢查和轉換 JSON 中的每個對象。 例如考慮使用Newtonsoft.Json庫進行 JSON 解析,您可以執行以下操作:

// considering your JSON string
string jsonString = "[{'MyObj':{'Foo':'Bar'}},{'MyObj':[{'Foo':'Bar1'},{'Foo':'Bar2'}]}]";

// parse your JSON into JTokens
var tokens = JToken.Parse(jsonString);

// iterate through  all the tokens
foreach (var token in tokens)
{
   // your token is a grand child
   JToken myObj = token.First.First;

   // check if the grand child is array
   if (myObj is JArray)
   {
      // cast the grand child token into MyObj list or array object
      IEnumerable<MyObj> objList = myObj.ToObject<List<MyObj>>();
      Console.WriteLine("converted to MyObj Array");
   }
   else if (myObj is JObject) // else if its a non array item
   {
       // cast the grand child token into MyObj object
       MyObj obj = myObj.ToObject<MyObj>();
       Console.WriteLine("converted to MyObj");
    }
}

// your MyObj Type will look like this:
public class MyObj 
{
   public string Foo { get; set; }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM