反序列化json对象并将内部对象转换为字符串值?

时间:2011-09-19 16:02:33

标签: c# json.net

我有一个返回json数据的web服务。我无法控制服务器端生成的json。

我像这样反序列化json:

JsonConvert.DeserializeObject<OuterObject>(jsonString);

问题是嵌入了内部对象(有很多嵌套的内部对象)。我没兴趣在我的应用程序中对它们进行建模。

json-data是这样的:

{ 
    id : "xyz",
    name : "Some Object",
    properties : {
        prop_1 : "foo",
        prop_2 : "bar"
    },
    inner_object : {
        id : "abc$1",
        name : "Inner Object Name",
        ....
        // a whole lot of stuff here
        // with more embedded objects
        ....
    }
}

我想将外部对象建模为一个简单的POCO,其中内部对象仅由(String)id引用,而不是对象引用。

public class Outer
{
    public String Id { get; internal set; }
    public String Name { get; internal set; }
    public Dictionary<String,String> Properties { get; internal set; }

    // Just keep the InnerObject Id, no real reference to an instance
    public String InnerObjectId { get; set; }
}

我想我可以编写一个JsonOuterObject版本,其中包含对JsonInnerObject的真实对象引用,并从那里构建我真正的OuterObject,之后扔掉其他对象......但这太蹩脚了。 (我不想在这样的提交中看到我的名字)

所以我现在正在使用Json.NET的IContractResolver(覆盖DefaultContractResolver),但看起来我在这里长途跋涉。

我是否缺少一些明显的Json.NET功能,可以在这里为我解决这个问题?

或许还有一些指示IContractResolver的哪些方法在这里很有意思?

编辑: .NET中的POJO显然是POCO

2 个答案:

答案 0 :(得分:3)

为外部类型创建自定义JsonConverter可以在反序列化对象时提供很大的灵活性。

这项工作要多得多,但值得努力。特别是如果您无法控制返回的JSON对象,并且您希望在客户端应用程序中对返回的数据进行不同的建模。

JsonConverter实现的内容覆盖了ReadJson方法

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

JsonReader是数据的标记化流。实现可以是这样的:

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;
}

您可以使用JsonConverterAttribute注释您的外部对象,或者将转换器传递给JsonConverter类的(重载)Deserialize(String json,params JsonConverter []转换器)方法

答案 1 :(得分:2)

一种方法是使用Newtonsoft.Json.Linq和动态类型,因为您实际上是在尝试(或被迫)弯曲类型安全规则。

    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"
        //}
    }

或者,您可以将Outer定义为:

    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; }
    }

这对我来说有点清洁。祝你好运。