C# DataContractJsonSerializer fails when value can be an array or a single item

人盡茶涼 提交于 2020-01-01 05:39:30

问题


I use the DataContractJsonSerializer to parse a json string into a object hierarchie. The json string looks like this:

{
    "groups": [
        {
            "attributes": [
                {
                    "sortOrder": "1",
                    "value": "A"
                },
                {
                    "sortOrder": "2",
                    "value": "B"
                }
            ]
        },
        {
            "attributes": {
                "sortOrder": "1",
                "value": "C"
            }
        }
    ]
}

As you can see the sub value of "attributes" can be an array or a single item. I found the code part where the problem occures:

[DataContract]
public class ItemGroup
{
    [DataMember(Name="attributes")]
    public List<DetailItem> Items  { get; set; }
}

This works for the first one but fails on the second one.

Has anyone an answer for this?

Thx


回答1:


If you control how the JSON is created then make sure that attributes is an array even if it only contains one element. Then the second element will look like this and parse fine.

    {
        "attributes": [{
            "sortOrder": "1",
            "value": "C"
        }]
    }



回答2:


As Daniel said, if you can control the creation of Json, it is better to continue that way. But if you can't, then you can use Json.Net library & the JsonObject class from this link to write some code like:

JObject o = (JObject)JsonConvert.DeserializeObject(input);
dynamic json = new JsonObject(o);
foreach (var x in json.groups)
{
      var attrs = x.attributes;
      if (attrs is JArray)
      {
           foreach (var y in attrs)
           {
               Console.WriteLine(y.value);
           }
      }
      else
      {
          Console.WriteLine(attrs.value);
      }
 }



回答3:


I tried to get this working with DataContractJsonSerializer, JavaScriptSerializer, and JSON.Net and none would deserialize directly to an object successfully in all cases. I used a similar approach as L.B, using JSON.Net, although without the use of dynamics and the extra JsonObject class. Adapting my code to your scenario would look something like the following:

private List<ItemGroup> ParseItemGroupList(string input)
    {
        JObject json = JObject.Parse(input);

        List<ItemGroup> groups = new List<ItemGroup>();
        JArray gArray = json["groups"] as JArray;
        foreach (var gToken in gArray)
        {
            ItemGroup newGroup = new ItemGroup();
            JToken attrToken = gToken["attributes"] as JToken;
            if (attrToken is JArray)
            {
                newGroup.Items = attrToken.Children().Select(MapDetailItem()).ToList();
            }
            else
            {
                newGroup.Items = new List<DetailItem>() { MapDetailItem().Invoke(attrToken) };
            }

            groups.Add(newGroup);
        }

        return groups;
    }

    private static Func<JToken, DetailItem> MapDetailItem()
    {
        return json => new DetailItem
        {
            SortOrder = (string)json["sortOrder"],
            Value = (string)json["value"]
        };
    }

Hopefully, someone will add a setting for JSON.Net to allow it to force deserialization to a collection with a single item rather than throwing an exception. It's a shame that you have to do all of the parsing manually when there is only one small portion of the JSON that doesn't parse correctly automatically.



来源:https://stackoverflow.com/questions/7647651/c-sharp-datacontractjsonserializer-fails-when-value-can-be-an-array-or-a-single

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