【问题标题】:JsonConvert string to CollectionJson将字符串转换为集合
【发布时间】:2018-04-25 17:54:52
【问题描述】:

我从一个 API 得到这个 json 格式:

"url_service": "",
"Description": null,
"Target": "5,6",
"Category ": "2"

我正在尝试将 json 反序列化为模型。问题在于“目标”字段,它应该是 int 的 ICollection。 这是我的模型:

public string Description{ get; set; }
public ICollection<int> Target{ get; set; }
public int Category { get; set; }

有没有办法在 Json 被序列化之前对其进行处理,以便从逗号分隔的字符串中创建一个集合?

【问题讨论】:

  • 如果您使用 Newtonsoft,您可能需要创建自己的 JsonConverter

标签: c# json deserialization


【解决方案1】:

与其尝试更改反序列化逻辑,不如让自己更轻松,只在模型中包含一个新属性?

public string Description{ get; set; }
public int Category { get; set; }

//Change this back to string, since that is what your JSON is
public string Target{ get; set; }

//Add a "TargetList" property that just reads from "Target" and turns into a List
public List<int> TargetList => Target.Split(',').Select(x => int.Parse(x)).ToList();

请注意,我的代码中没有错误处理,因此您必须进行相应的修改。

【讨论】:

  • 谢谢,我没有想到要在模型中添加一个额外的属性。
【解决方案2】:

是的,让您的 C# 类实现 ISerializable 接口。您可以实现 OnDeserialized()、OnSerialized() 函数。

参考.NET Deserialisation with OnDeserializing and OnDeserialized

【讨论】:

    【解决方案3】:

    您的 JSON 片段描述的不是整数集合而是字符串。正确的应该是

    "Target": [ 5, 6 ],

    转换为

    的 JSON 模式
     "Target": {
         "type": ["array"],
         "items": { "type": "integer"}
        },
    

    如果您无法控制结果,则创建另一个属性,该属性将是整数的结果,例如

       private string _target;
       public string Target {  get { return _target; } 
                               set { 
                                     _target = value; 
                                     Targets = Regex.Matches(_target, @"(\d+)")
                                                    .OfType<Match>()
                                                    .Select(mt => int.Parse(mt.Value))
                                                    .ToList();
       public List<int> Targets { get; set; }
    

    【讨论】:

      【解决方案4】:

      目标字段在您的 json 中是字符串类型,因此序列化程序将尝试将其作为字符串读取。 您可以使用转换器来否决,例如使用Newtonsoft Json

      假设您的数据结构定义如下:

      public class Data {
          public string Description{ get; set; }
          public ICollection<int> Target{ get; set; }
          public int Category { get; set; }
      }
      

      然后您可以创建自己的JsonConverter,如下所示:

      public class DataConverter : JsonConverter {
      
          public override bool CanWrite => false;
      
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
              throw new NotImplementedException();
          }
      
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
      
              var jObject = JObject.Load(reader);
      
              var data = new Data();
      
              if (jObject.TryGetValue("Description", out JToken jDescription)) {
                  data.Description = jDescription.Value<string>();
              }
              if (jObject.TryGetValue("Target", out JToken jTarget)) {
                  data.Target = ToTarget(jTarget, serializer);
              }
              if (jObject.TryGetValue("Category", out JToken jCategory)) {
                  data.Category = jCategory.Value<int>();
              }
      
              return req;
      
          }
      
          private static ICollection<int> ToTarget( JToken jTarget, JsonSerializer serializer ) {
      
              int defaultValue = -1;
              var target = new List<int>();
              var collection = jTarget.Value<string>().Split(',');
              foreach (string str in collection)
                  if (int.TryParse(str, out int number))
                      target.Add(number);
                  else
                      target.Add(defaultValue);
      
              return target;
      
          }
      
          public override bool CanConvert(Type objectType) => objectType == typeof(Data);
      
      }
      

      然后您可以使用以下代码进行反序列化:

      var jsonSettings = new JsonSerializerSettings();
      jsonSettings.Converters.Add(new DataConverter);
      Data data = JsonConvert.DeserializeObject<Data>(yourJsonString, jsonSettings);
      

      进一步考虑:这种方法在您的数据定义和数据解析逻辑之间提供了清晰的分离,从而使您的数据结构和定义与任何 json 特定信息和解析逻辑保持干净。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-24
        • 2020-11-30
        • 1970-01-01
        • 1970-01-01
        • 2018-06-28
        相关资源
        最近更新 更多