Deserialize json objects and transform inner objects to a string value?

雨燕双飞 提交于 2019-12-05 11:53:53

One approach would be to use Newtonsoft.Json.Linq and dynamic types since you are essentially trying to (or being forced to) bend type safety rules.

    public class Outer
    {            
        [JsonProperty(PropertyName = "id")]
        public String Id { get; internal set; }
        [JsonProperty(PropertyName = "name")]
        public String Name { get; internal set; }
        [JsonProperty(PropertyName = "properties")]
        public Dictionary<String, String> Properties { get; internal set; }
        [JsonProperty(PropertyName = "inner_object")]
        public dynamic InnerObjectId { get; set; }
    }

    public void InnerObjectAsDynamic()
    {
        const string json = @"{""id"":""xyz"",""name"":""Some Object"",""properties"":{""prop_1"":""foo"",""prop_2"":""bar""},""inner_object"":{""id"":""abc$1"",""name"":""Inner Object Name""}}";
        var outer = JsonConvert.DeserializeObject<Outer>(json);
        var innerObjectJson = outer.InnerObjectId.ToString();
        Console.WriteLine(innerObjectJson);
        //{
        //  "id": "abc$1",
        //  "name": "Inner Object Name"
        //}
    }

Alternatively, you could define Outer as:

    public class Outer
    {
        [JsonProperty(PropertyName = "id")]
        public String Id { get; internal set; }
        [JsonProperty(PropertyName = "name")]
        public String Name { get; internal set; }
        [JsonProperty(PropertyName = "properties")]
        public Dictionary<String, String> Properties { get; internal set; }
        [JsonProperty(PropertyName = "inner_object")]
        public Newtonsoft.Json.Linq.JObject InnerObjectId { get; set; }
    }

This is a little cleaner to me. Best of luck.

Creating a custom JsonConverter for the Outer-type allows you a lot of flexibility when deserializing objects.

It's considerably more work, but it can be worth the effort. Especially if you have no control over the returned JSON object and you would like to model the returned data differently in your client application.

The meat of the JsonConverter implementation is overriding the ReadJson method

public override object ReadJson(JsonReader reader,
                                Type objectType,
                                object existingValue,
                                JsonSerializer serializer)

The JsonReader is a tokenized stream of your data. An implementation could go like this:

public override object ReadJson(JsonReader reader,
                                Type objectType,
                                object existingValue,
                                JsonSerializer serializer)
{
    var outer = new Outer()

    while (reader.TokenType != JsonToken.EndObject)
    {
        if (reader.TokenType == JsonToken.PropertyName)
        {
            var propertyName = reader.Value.ToString();
            reader.Read();

            switch (propertyName)
            {
                case "id":
                    outer.Id = serializer.Deserialize<String>(reader);
                    break;
                case "id":
                    outer.Properties = serializer.Deserialize<Dictionary<String,String>>(reader);
                    break;
                case "inner_object"
                    var inner = serializer.Deserialize<Inner>(reader);
                    outer.InnerObjectId = inner.Id;
                    break;
                [...more cases...]
                default:
                    serializer.Deserialize<object>(reader);
                    break;
                }
                reader.Read(); // consume tokens in reader
            }
        } else {
            // throw exception ?
        }
    }

    return outer;
}

You can annotate your Outer object with the JsonConverterAttribute or pass a long the converter to the (overloaded) Deserialize(String json, params JsonConverter[] converters) method of the JsonConverter class

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!