【问题标题】:Using a Custom Json Deserializer to create a new object使用自定义 Json 反序列化器创建新对象
【发布时间】:2020-07-27 13:33:24
【问题描述】:

我有以下课程。我正在尝试将 Json 反序列化为这些 LookUpData 对象的数组:

 [DataContract]
    public class LookUpData
    {
        [DataMember]
        public string Id { get; set; }
        [DataMember]
        public GeographyPoint Location { get; set; }
    }
}

Json 数据如下所示:

{
    "Id": "123",
    "Location": {
      "Latitude": 1,
      "Longitude": -1,
      }
    }
  },

我想创建一个自定义的 Json 反序列化器,以便在读取 Json 并点击“位置”时,它将根据纬度和经度值创建一个新的 GeographyPoint 类型。

我已经在 Custom Json Serializer 上查看了 Newtonsoft 的文档以及有关 Stack Overflow 的有用答案,例如 Custom Deserialization using Json.NET,但我找不到如何实际创建的示例> 反序列化时的新类型。例如,我目前使用标准反序列化器收到的错误是“无法创建 Microsoft.Spatial.GeographyPoint 类型的实例。类型是接口或抽象类,不能实例化”。

如果有人能在这里指出正确的方向,我将不胜感激。谢谢!

【问题讨论】:

  • 我不明白你的问题。反序列化时,它总是为所有内容创建一个“新”实例。
  • JsonConvert.DeserializeObject<List<LookUpData>>(jsonString) 有什么问题?
  • 我已经更新了我的问题@rory.ap 并提供了更多解释 - 抱歉,这不清楚。我需要创建一个从经度和纬度值创建的新“类型”(GeographyPoint')。目前使用标准反序列化器时,我收到错误消息:'无法创建 Microsoft.Spatial.GeographyPoint 类型的实例。类型是接口或抽象类,不能实例化”。
  • 使用LatitudeLongitude 道具创建自己的MyGeographyPoint 类...在您的类中创建这种类型的私有字段并让默认反序列化反序列化到它...然后添加getter第一次使用GeographyPoint.Create 和来自MyGeographyPoint 的数据创建真正的GeographyPoint 并返回它(类似于链接中的LB 答案)
  • 是否需要序列化以及反序列化?

标签: c# .net json.net


【解决方案1】:

您可以为GeographyPoint 类型编写一个简单的JsonConverter,如下所示。此实现使用JObject 作为轻松读取(和写入)JSON 的方法。创建GeographyPoint 实例的关键是使用该类型提供的静态Create 方法。

class GeographyPointConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(GeographyPoint).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken obj = JToken.Load(reader);
        if (obj.Type == JTokenType.Null) return null;
        double latitude = (double)obj["Latitude"];
        double longitude = (double)obj["Longitude"];
        return GeographyPoint.Create(latitude, longitude);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        GeographyPoint point = (GeographyPoint)value;
        JObject obj = new JObject(
            new JProperty("Latitude", new JValue(point.Latitude)),
            new JProperty("Longitude", new JValue(point.Longitude))
        );
        obj.WriteTo(writer);
    }
}

要使用转换器,只需将[JsonConverter] 属性添加到LookUpData 类中的Location 属性:

public class LookUpData
{
    public string Id { get; set; }

    [JsonConverter(typeof(GeographyPointConverter))]
    public GeographyPoint Location { get; set; }
}

注意:在使用 Json.Net 时,您实际上并不需要 [DataContract][DataMember] 属性,除非您需要选择加入语义——这意味着您需要明确识别序列化和反序列化中包含哪些类和成员.如果省略这些属性,则默认包含所有类和成员,这似乎是您的意图。

工作演示:https://dotnetfiddle.net/YNo1vP

【讨论】:

  • 感谢@BrianRogers - 真的很有帮助!只是想知道当 'Location' 为空且无法反序列化时正确的处理方法是什么?
  • 如果位置可能为空,那么您需要在ReadJson 中检查它并返回空或可选地创建一个默认地理点。我已经用这张支票更新了我的答案。请注意,我必须改用 JToken.Load 而不是 JObject.Load
  • 非常感谢@BrianRogers。我收到此错误:“'从 JsonReader 读取 JObject 时出错。当前 JsonReader 项目不是对象:EndObject。路径'[0].Location',第 21 行,位置 5。'”我猜这是因为我的自定义反序列化器正在尝试反序列化空对象?
  • 您是否将JObject.Load 更改为JToken.Load,如图所示?我还更新了小提琴以在那里显示工作代码。
猜你喜欢
  • 2021-06-24
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多