【问题标题】:JSON Deserializing modified class. Custom JSON Deserialize methodJSON 反序列化修改的类。自定义 JSON 反序列化方法
【发布时间】:2019-04-16 22:46:39
【问题描述】:

我有一个经常序列化和反序列化的类。 它的一个字段曾经是一个字符串来表示一条道路,但后来被更改为它自己的类。

class Foo
{
    public string RoadRef;
}

现已改为:

class Foo
{
    public Road RoadRef;
}

class Road
{
    public Road(string val)
    {
        Lane = val[0];
        Number = int.Parse(val.Substring(1));
    }

    public char Lane;
    public int Number = 1;
}

现在,当我尝试从使用旧版本的类序列化的字符串中反序列化时,我遇到了错误。我有很多旧的序列化文件,我不想返回并重新序列化为新格式,尤其是因为这样的更改可能会再次发生。

我应该能够为JsonConvert.Deserialize 指定一个自定义方法来反序列化(和序列化)对吧? 有没有更好的方法来处理这个问题?

到目前为止,我最接近的是在构造函数上方添加一个 [JsonConstructor] 属性,正如建议的 here 那样,但这对反序列化崩溃没有帮助。

原始 JSON 如下所示:{"RoadRef":"L1"} 它抛出这个异常:

Newtonsoft.Json.JsonSerializationException: '错误转换值 “L1”输入“路”。路径“RoadRef”,第 1 行,位置 15。'

ArgumentException:无法从 System.String 转换或转换为 Vis_Manager.Road。

【问题讨论】:

  • 你的 Json 是什么样的?
  • 我认为您可能需要custom JsonConverter<T> 来执行此操作。
  • @AndrewE 现在添加了 JSON 和异常
  • 看起来可能是因为它不知道 L & 1 是两个不同的对象。
  • 你试过投射吗?

标签: c# json json.net


【解决方案1】:

正如 stuartd 建议的那样,您可以使用自定义 JsonConverter 来明确说明如何将字符串转换为您的数据类型。

void Main()
{
    string json = @"{""RoadRef"":""L1""}";
    var data = JsonConvert.DeserializeObject<Foo>(json);
}

public class RoadConverter : JsonConverter<Road>
{

    public override bool CanWrite => false;

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

    public override Road ReadJson(JsonReader reader, Type objectType, Road existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        if (reader.ValueType != typeof(string))
            return (Road)serializer.Deserialize(reader, objectType);

        var data = reader.Value as string;
        return new Road(data);
    }
}


public class Foo
{
    [JsonConverter(typeof(RoadConverter))]
    public Road RoadRef { get; set; }
}

public class Road
{
    public Road(string val)
    {
        Lane = val[0];
        Number = int.Parse(val.Substring(1));
    }

    public char Lane { get; set; }
    public int Number { get; set; } = 1;
}

如果您不想使用 Attribute 装饰器并使您的模型不受任何序列化问题的影响,您可以将其用作 DeserialzeObject 方法的参数

var data = JsonConvert.DeserializeObject<Foo>(json, new RoadConverter());

【讨论】:

    【解决方案2】:

    您可以使用implicit 运算符直接从字符串转换,而不是使用自定义JsonConverter

    public class Road
    {
        public Road(string val)
        {
            Lane = val[0];
            Number = int.Parse(val.Substring(1));
        }
    
        public char Lane { get; set; }
        public int Number { get; set; } = 1;
    
        public static implicit operator Road(string val)
        {
            return new Road(val);
        }
    }
    

    【讨论】:

      【解决方案3】:

      我的解决方案是将字符串中的overriding cast 添加到类中。 JSON Deserialize 方法尝试将字符串值显式转换为类,这现在是可能的。

      public Road(string val)
      {
          Lane = val[0];
          Number = int.Parse(val.Substring(1));
       }
      
      public static explicit operator Road(string val)
      {
          return new Road(val);
      }
      

      【讨论】:

        猜你喜欢
        • 2022-09-23
        • 1970-01-01
        • 1970-01-01
        • 2014-08-02
        • 1970-01-01
        • 1970-01-01
        • 2011-04-12
        • 2013-01-18
        • 1970-01-01
        相关资源
        最近更新 更多