当值既可以是数组又可以是单个项目时,C# DataContractJsonSerializer 失败

5

我使用DataContractJsonSerializer将一个JSON字符串解析成对象层次结构。JSON字符串的格式如下:

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

正如您所见,“attributes”子值可以是一个数组或单个项。我找到了问题发生的代码部分:

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

这个方法可以用于第一个,但是在第二个上失败了。

有人知道答案吗?

谢谢。


为什么这个JSON不一致?修复源代码是否可能? - Marc Gravell
它是如何失败的?出现了什么错误? - bryanmac
3个回答

3
如果您控制JSON的创建,请确保attributes是一个数组,即使它只包含一个元素。那么第二个元素将看起来像这样,并且可以正确解析。
    {
        "attributes": [{
            "sortOrder": "1",
            "value": "C"
        }]
    }

3

正如Daniel所说,如果您可以控制Json的创建,最好继续使用这种方式。但是如果您不能控制,那么您可以使用Json.Net库和此链接中的JsonObject类编写一些代码,例如:

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

1

我尝试使用DataContractJsonSerializer、JavaScriptSerializer和JSON.Net来实现这个功能,但在所有情况下都无法直接将其反序列化为对象。我采用了与L.B类似的方法,使用了JSON.Net,但没有使用动态和额外的JsonObject类。将我的代码适应到您的场景中,看起来会像以下内容:

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

希望有人能够添加一个设置到JSON.Net中,使其强制反序列化为只有一个项的集合而不是抛出异常。当只有JSON的一小部分无法自动解析时,你必须手动进行所有解析,这真是太遗憾了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接