【问题标题】:Deserializing some JSON properties to a child object with Newtonsoft.Json使用 Newtonsoft.Json 将一些 JSON 属性反序列化为子对象
【发布时间】:2018-06-22 18:48:49
【问题描述】:

我有这个 JSON 格式的字符串:

{
    "hr": "12:56",
    "vs": [
        {
            "pre": "73833",
            "a": true,
            "posx": "-46.688962875",
            "posy": "-23.632046625"
        },
        {
            "pre": "73722",
            "a": true,
            "posx": "-46.773388125",
            "posy": "-23.68939025"
        }                               
    ]
}

我想将 JSON 反序列化为此类:

public class Tracking
{
    [JsonProperty(PropertyName = "hr")]
    public string Hour { get; set; }

    [JsonProperty(PropertyName = "vs")]
    public IList<Vehicle> Vehicles { get; set; }
}

Vehicle 类目前具有以下属性:

public class Vehicle
{
    [JsonProperty (PropertyName = "pre")]
    public string Prefix {get; set; }

    [JsonProperty (PropertyName = "posx")]
    public string Y {get; set; }

    [JsonProperty (PropertyName = "posy")]
    public string X {get; set; }
}

相反,我想将posxposy 属性反序列化为一个名为Position 的子类,并带有XY 属性:

public class Position
{
    [JsonProperty (PropertyName = "posx")]
    public string Y {get; set; }

    [JsonProperty (PropertyName = "posy")]
    public string X {get; set; }
}

导致以下Vehicle类:

public class Vehicle
{
    [JsonProperty (PropertyName = "pre")]
    public string Prefix {get; set; }

    public Position Position {get; set; }
}

我打算在我系统上的更多地方使用Position 类,并且不想重复这些属性。但是使用新结构反序列化时,Position 属性返回 null。

{
    "hr": "13:08",
    "vs": [
        {
            "pre": "73833",
            "a": true,
            "Position": null
        },
        {
            "pre": "73722",
            "a": true,
            "Position": null
        }    
    ]
}

我该怎么做才能使这段代码正常工作?

【问题讨论】:

  • 反序列化什么?我想我们需要看看你想要反序列化的 json 是怎样的
  • 更新问题
  • 您应该将序列化部分与程序的其余部分分开。如果您想更改对象层次结构,请制作一个适配器,否则您很快就会在 hack 上苦苦挣扎以获得想要的 json 格式。最好将两者分开。

标签: c# asp.net json asp.net-web-api json.net


【解决方案1】:

有几种方法可以实现您想要的结果。
最快的方法是对原来的 Vehicle 类进行一些更改:

  1. 添加一个新的Position 属性并用[JsonIgnore] 标记它
  2. XY 属性设为私有并更改它们,以便它们写入和读取Position 对象。

生成的类应如下所示:

public class Vehicle
{
    [JsonProperty(PropertyName = "pre")]
    public string Prefix { get; set; }

    [JsonIgnore]
    public Position Position { get; set; }

    [JsonProperty(PropertyName = "posx")]
    private string Y
    {
        get { return Position != null ? Position.Y : null; }
        set
        {
            if (Position == null) { Position = new Position(); }
            Position.Y = value;
        }
    }

    [JsonProperty(PropertyName = "posy")]
    private string X
    {
        get { return Position != null ? Position.X : null; }
        set
        {
            if (Position == null) { Position = new Position(); }
            Position.X = value;
        }
    }
}

演示小提琴:https://dotnetfiddle.net/5zT5Rf


如果您不喜欢这个想法,另一种选择是为您的 Vehicle 类制作自定义 JsonConverter

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        Vehicle veh = new Vehicle();
        serializer.Populate(obj.CreateReader(), veh);
        Position pos = new Position();
        serializer.Populate(obj.CreateReader(), pos);
        veh.Position = pos;
        return veh;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Vehicle veh = (Vehicle)value;
        JObject obj = JObject.FromObject(veh.Position, serializer);
        obj.AddFirst(new JProperty("pre", veh.Prefix));
        obj.WriteTo(writer);
    }
}

然后,用 [JsonConverter] 属性标记您的 Vehicle 类,以将其与转换器绑定:

[JsonConverter(typeof(VehicleConverter))]
public class Vehicle
{
    [JsonProperty(PropertyName = "pre")]
    public string Prefix { get; set; }

    public Position Position { get; set; }
}

演示小提琴:https://dotnetfiddle.net/HRSRa9

【讨论】:

    【解决方案2】:

    如果您使用 Newtonsoft,您应该能够使用 Vehicle myVehicle = JsonConvert.DeserializeObject&lt;Vechicle)(myString) 进行反序列化,因为:

    • 您正在使用帖子底部的课程。
    • 您正在反序列化从该类序列化的 Json。如果您以前的 Vehicle 类中的旧 Json 将无法工作,除非您专门处理这种情况(如果第一次反序列化失败,请尝试旧类,如果成功将其转换为新的 Vehicle 类。

    【讨论】:

    • 您的 Json 似乎与您的 Vehicle 类不匹配。 JsonProperty 需要匹配 Json 字符串中的名称。 "p" => "pre", "px" => "posx" 等等...
    • 您的 json 仍然与您的班级不匹配。如果您遇到数据结构问题,请尝试使用app.quicktype.io
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    相关资源
    最近更新 更多