当前位置: 首页 > 面试题库 >

Newtonsoft JSON.NET解析为自定义键/值对对象的数组

花高爽
2023-03-14
问题内容

我在解析给定的JSON数据时遇到了一个奇怪的问题。我有这个JSON结构:

{"value":[
  {"street":"Karlova 25"},
  {"city":"Prague"},
  {"gpsLat":"50.1571"},
  {"gpsLon":"15.0482"}
]}

如何使用Newtonsoft JSON.NET库解析此结构?我尝试使用自己的JsonConverter类:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){
  JArray jarray = (JArray)((JTokenReader)reader).CurrentToken;
  List<AddressValue> values = new List<AddressValue>();
  foreach (var jobj in jarray.Children<JObject>()){
    foreach (JProperty prop in jobj.Properties()){
      values.Add(new AddressValue() { Label = prop.Name, Value = prop.Value.ToString() });
    }
  }
  return values.ToArray();
}

class AddressValue{
  public string Label { get; set; }
  public string Value { get; set; }
}

但我有一个例外:

Exception thrown: 'Newtonsoft.Json.JsonSerializationException' in Newtonsoft.Json.DLL

Additional information: Unexpected token when deserializing object: StartObject. Path 'value[0]'.

编辑:我也试图将其保存到字典:

 [JsonProperty(PropertyName = "value")]
 public Dictionary<string, string> Value{get; set;}

但我还有一个例外:

$exception  {"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.String]' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath 'param.value'."}

我做错了什么?谢谢您的回答。


问题答案:

您似乎想要Dictionary<string, string>在JSON中将a表示为对象数组,其中每个嵌套对象都有一个来自字典的键和值。您可以使用以下转换器进行操作:

public class DictionaryToDictionaryListConverter<TKey, TValue> : JsonConverter 
{
    class DictionaryDTO : Dictionary<TKey, TValue>
    {
        public DictionaryDTO(KeyValuePair<TKey, TValue> pair) : base(1) { Add(pair.Key, pair.Value); }
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(IDictionary<TKey, TValue>).IsAssignableFrom(objectType) && objectType != typeof(DictionaryDTO);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var token = JToken.Load(reader);
        var dict = (IDictionary<TKey, TValue>)(existingValue as IDictionary<TKey, TValue> ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
        if (token.Type == JTokenType.Array)
        {
            foreach (var item in token)
                using (var subReader = item.CreateReader())
                    serializer.Populate(subReader, dict);
        }
        else if (token.Type == JTokenType.Object)
        {
            using (var subReader = token.CreateReader())
                serializer.Populate(subReader, dict);

        }
        return dict;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dict = (IDictionary<TKey, TValue>)value;
        // Prevent infinite recursion of converters by using DictionaryDTO
        serializer.Serialize(writer, dict.Select(p => new DictionaryDTO(p)));
    }
}

然后在容器类中使用它,如下所示:

public class RootObject
{
    [JsonProperty("value")]
    [JsonConverter(typeof(DictionaryToDictionaryListConverter<string, string>))]
    public Dictionary<string, string> Value { get; set; }
}

请注意,如果键不是唯一的,转换器将在读取过程中引发异常。

更新资料

对于AddressValue您可以使用下面的转换器:

public class AddressValueConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(AddressValue);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var addressValue = (existingValue as AddressValue ?? new AddressValue());
        var token = JObject.Load(reader);
        var property = token.Properties().SingleOrDefault();
        if (property != null)
        {
            addressValue.Label = property.Name;
            addressValue.Value = (string)property.Value;
        }
        return addressValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var addressValue = (AddressValue)value;
        serializer.Serialize(writer, new Dictionary<string, string> { { addressValue.Label, addressValue.Value } });
    }
}

然后按以下方式使用它:

[JsonConverter(typeof(AddressValueConverter))]
public class AddressValue
{
    public string Label { get; set; }
    public string Value { get; set; }
}

public class RootObject
{
    [JsonProperty("value")]
    public List<AddressValue> Value { get; set; }
}

演示在这里摆弄了这两种选择。



 类似资料:
  • 问题内容: 我需要反序列化json,它是日期/长值的数组。这是返回的JSON的示例: 使用GSON,我可以将其反序列化为,但希望能够将其转换为类似以下内容的方法: 我似乎找不到一种方法来指示GSON将JSON映射的键/值映射到我的自定义类中的日期/值字段。有没有办法做到这一点,还是地图列表是唯一的路线? 问题答案: 您需要编写一个自定义解串器。您还需要使用可以实际解析的时区格式。无论是也将匹配,这

  • 问题内容: 我必须怎么做才能将自定义类型的对象用作Python字典中的键(我不希望“对象id”用作键),例如 如果名称和位置相同,我想将MyThing用作相同的键。从C#/ Java开始,我习惯于重写并提供一个equals和hashcode方法,并保证不会突变该hashcode依赖的任何内容。 我必须在Python中做什么才能完成此任务?我应该吗? (在一个简单的例子中,就像这里一样,也许最好将一

  • 问题内容: 说我的课很简单 我希望将此类s 的集合存储在People类的属性中,该属性是类型为Person的数组 也许我做到这一点如下 问题:请问我如何检查people.list是否包含实例alex? 我很想尝试的简单尝试 称一个错误 问题答案: 有两个功能: 编译器在抱怨是因为编译器知道不是,因此需要一个谓词,但不是谓词。 如果阵列中的人员是(不是),则可以使用: 由于它们不相等,因此可以将第二

  • (假设Magic是4个字节,Command是1个字节,Options是2个字节,Bodysize是4个字节,并且body本身的长度是可变的。)我如何在不使用任何第三方库的情况下解析它? 通常我会说,可以这样做来存储数据包数据: 问题是,我首先提供头信息,然后以一种笨拙的方式添加正文数据。包对象有一个在不完整状态下可以访问的时间点。 我是用C++开发的,对于通过套接字发送和接收数据,使用了boost

  • 我在将一些数据索引到ElasticSearch时遇到了一个问题 这是背景。我想索引下面的内容到弹性搜索如下,其中有一个[值]命名字段: 当我建立索引时,我从ES服务器得到一个异常:“type:“mapper_parsing_exception”,“reason:“未能解析[invokingMethods.value],“caused_by:“{”type:“非法参数_exception”,“rea

  • 问题内容: 我想将对象数组转换为javascript中具有键值对的对象。 我如何将其转换为诸如 我希望大多数浏览器都支持它。 问题答案: 您可以使用和传播语法来创建具有给定对象数组的单个对象。