【问题标题】:newtonsoft.json deserializing logicnewtonsoft.json 反序列化逻辑
【发布时间】:2015-05-12 20:12:20
【问题描述】:

我正在尝试在反序列化期间将带有例如 [1,2,3] 的 json 字符串解析为数组。

这是我的 json 数据:

[
    {
        "id": "1",
        "district": "1",
        "lon": "4.420650000000000000",
        "lat": "51.21782000000000000",
        "bikes": "19",
        "slots": "14",
        "zip": "2018",
        "address": "Koningin Astridplein",
        "addressNumber": null,
        "nearbyStations": "3,4,5,24",
        "status": "OPN",
        "name": "001- Centraal Station - Astrid"
    }
]

这是我当前映射到常规字符串的 c#,我希望它是一个整数数组。

var AvailabilityMap = new[] { new Station() };
var data = JsonConvert.DeserializeAnonymousType(json, AvailabilityMap);

public class Station
{
    public int Id { get; set; }
    public double Lon { get; set; }
    public double Lat { get; set; }
    public int Bikes { get; set; }
    public int Slots { get; set; }
    public string Address { get; set; }
    public string NearbyStations { get; set; }
    public string Status { get; set; }
    public string Name { get; set; }
}

到目前为止,我还没有找到以正确方式执行此操作的方法,而无需再次循环遍历我当前的数组..

【问题讨论】:

  • 您是否尝试将附近的Stations 作为数组?

标签: c# json.net


【解决方案1】:

创建自定义转换器。像这样的:

public class StringToIntEnumerable : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override bool CanWrite
    {
        get
        {
            return false;    // we'll stick to read-only. If you want to be able 
                             // to write it isn't that much harder to do.
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Note: I've skipped over a lot of error checking and trapping here
        // but you might want to add some
        var str = reader.Value.ToString();
        return str.Split(',').Select(s => int.Parse(s));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

现在使用JsonConverterAttribute 更改您的类以使用转换器:

public class Station
{
    public int Id { get; set; }
    public double Lon { get; set; }
    public double Lat { get; set; }
    public int Bikes { get; set; }
    public int Slots { get; set; }
    public string Address { get; set; }
    [JsonConverter(typeof(StringToIntEnumerable))]
    public IEnumerable<int> NearbyStations { get; set; }  // or List<int> or int[] if 
                                                          // you prefer, just make 
                                                          // sure the convert returns 
                                                          // the same type
    public string Status { get; set; }
    public string Name { get; set; }
}

现在反序列化:

var stations = JsonConvert.DeserializeObject<List<Station>>(json);

【讨论】:

    【解决方案2】:

    Here is a working fiddle 使用自定义 JsonConverter

    我们正在做的是将您的 CSV 值转换为适当的 JSON 数组我们将整个 JSON 字符串转换为 Station 对象。

    自定义JsonConverter

    ReadJson 读取 JSON 字符串。首先,它将 JSON 加载到 JObject 中。接下来,它获取 nearbyStations 属性并将其从简单的 CSV 字符串更改为 JavaScript 数组。它通过将 CSV 包裹在方括号中来实现这一点。最后,我们使用JsonSerializer 填充我们的目标对象并返回它。

    CanWrite 设置为false,因为这个JsonConverter 只允许读取JSON 而不能写入JSON。因此,我们不需要实现WriteJsonCanConvert 测试以确保目标对象是Station

    public class StationConverter : JsonConverter
    {
        public override object ReadJson(
            JsonReader r, Type t, object v, JsonSerializer s)
        {
            JObject jObject = JObject.Load(r);
    
            var prop = jObject.Property("nearbyStations");
            var wrapped = string.Format("[{0}]", prop.Value);
            JArray jsonArray = JArray.Parse(wrapped);
            prop.Value = jsonArray;
    
            var target = new Station();
            s.Populate(jObject.CreateReader(), target);
    
            return target;
        }
    
        public override void WriteJson(JsonWriter w, object v, JsonSerializer s)
        {
            throw new NotImplementedException("Unnecessary: CanWrite is false.");
        }
    
        public override bool CanWrite
        {
            get { return false; }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof (Station);
        }
    }
    

    Station 类更改为int[]

    要使上述JsonConverter 起作用,请将您的NearbyStations 属性更改为int[]

    public int[] NearbyStations
    {
        get;
        set;
    }
    

    使用示例with Live Fiddle

    这是一个如何使用它的例子:

    var AvailabilityMap = 
        JsonConvert.DeserializeObject<Station[]>(json, new StationConverter());
    
    Console.WriteLine(AvailabilityMap[0].NearbyStations[0]);
    

    【讨论】:

      【解决方案3】:

      正确的答案是正确格式化输入。在这种情况下:

       "nearbyStations": ["3","4","5","24"]
      

      但我也遇到过类似的情况,数据无法更新,所以必须找到解决办法。最简单的方法是制作一个不会被序列化器/反序列化器触及的 getter/setter。不幸的是,您不能使用开箱即用的序列化程序忽略公共属性。因此,您必须做一些巧妙的变通方法,例如读取 DTO 并使用业务对象进行实际操作。

      public class StationDTO
      {
          public int Id { get; set; }
          public double Lon { get; set; }
          public double Lat { get; set; }
          public int Bikes { get; set; }
          public int Slots { get; set; }
          public string Address { get; set; }
          public string NearbyStations { get; set; }
          public string Status { get; set; }
          public string Name { get; set; }
      }
      

      ...

      public class Station : StationDTO
      {
          public List<string> NearbyStationsList
          { 
              get 
              {
                  return NearbyStations.Split(',');
              }
      
              set
              {
                  NearbyStations = string.Join(",", value);
              }
          }
      }
      

      更多信息:Newtonsoft ignore attributes?

      【讨论】:

      • 我无法控制外部数据,所以感谢您的提示。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 2020-10-09
      • 2020-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      相关资源
      最近更新 更多