简体   繁体   English

JSON反序列化修改后的类。 自定义JSON反序列化方法

[英]JSON Deserializing modified class. Custom JSON Deserialize method

I had a class that I was regularly serializing and deserializing. 我有一个定期进行序列化和反序列化的类。 One of its fields used to be a string to represent a road, but has since been changed to its own class. 它的一个字段曾经是代表道路的字符串,但此后已更改为自己的类。

class Foo
{
    public string RoadRef;
}

Has now been changed to: 现在已更改为:

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

Now I'm getting errors when I try to deserialize from strings that were serialized with the old version of the class. 现在,当我尝试从使用该类的旧版本序列化的字符串中反序列化时,我遇到了错误。 I have a lot of old serialized files that I don't want to go back and reserialize to the new format, especially since changes like this will likely happen again. 我有很多旧的序列化文件,我不想返回并重新序列化为新格式,尤其是因为这样的更改可能会再次发生。

I should be able to specify a custom method to Deserialize (and Serialize) for JsonConvert.Deserialize right? 我应该能够为JsonConvert.Deserialize指定一个自定义方法来反序列化(和序列化),对吗? Is there a better approach to deal with this problem? 有没有更好的方法来解决这个问题?

The closest I've got so far is adding a [JsonConstructor] attribute above the constructor as suggested here , but it didn't help the deserializing crashes. 到目前为止,我最接近的是如此处建议的构造函数上方添加[JsonConstructor]属性,但这对反序列化崩溃没有帮助。

The original JSON looks like this: {"RoadRef":"L1"} It throws this exception: 原始JSON如下所示:{“ RoadRef”:“ L1”}它引发以下异常:

Newtonsoft.Json.JsonSerializationException: 'Error converting value "L1" to type 'Road'. Newtonsoft.Json.JsonSerializationException:'将值“ L1”转换为“ Road”类型时出错。 Path 'RoadRef', line 1, position 15.' 路径“ RoadRef”,第1行,位置15。”

ArgumentException: Could not cast or convert from System.String to Vis_Manager.Road. ArgumentException:无法将System.String强制转换或转换为Vis_Manager.Road。

As stuartd suggest, you could use a custom JsonConverter to explicitly say how to convert a string to your data type. 正如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;
}

If you don't want to use Attribute decorator and keep your model out of any serialization concern, you can use it as parameter of DeserialzeObject method 如果您不想使用属性装饰器并使模型脱离任何序列化问题,则可以将其用作DeserialzeObject方法的参数

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

Rather than using a custom JsonConverter you could use the implicit operator to convert directly from a string: 您可以使用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);
    }
}

My solution was to add an overriding cast from string to the class. 我的解决方案是将一个从字符串的重写类型添加到类中。 The JSON Deserialize method tries to explicitly cast the string value to the class, which is now possible. 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM