【发布时间】:2019-10-10 13:09:21
【问题描述】:
如果我有这个 JSON,其中有一个带有标签 version、generator、om3s 和 elements 的标头。 elements 可以是 node 或 way 类型,并且关联的 JSON 密钥因类型而异。我正在尝试使用 JsonSubTypes 将每个元素类型转换为 C# 类。
示例 JSON:
[
{
"version": 0.6,
"generator": "Overpass API 0.7.55.7 8b86ff77",
"osm3s": {
"timestamp_osm_base": "2019-05-21T18:03:02Z",
"copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
},
"elements": [
{
"type": "node",
"id": 4949106384,
"lat": 32.2686857,
"lon": -107.738218,
"tags": {
"highway": "turning_circle"
}
},
{
"type": "way",
"id": 14527404,
"nodes": [
142882281,
3048075541,
1598998260
],
"tags": {
"highway": "residential",
"name": "West Apple Street",
"tiger:cfcc": "A41",
"tiger:county": "Luna, NM",
"tiger:name_base": "Apple",
"tiger:name_direction_prefix": "W",
"tiger:name_type": "St",
"tiger:reviewed": "no"
}
}
]
}
]
我正在尝试使用以下方法对其进行反序列化:
var json = JsonConvert.DeserializeObject<OSMdata>(jsonText);
OSMdata 的样子:
[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(Element.Node), "node")]
[JsonSubtypes.KnownSubType(typeof(Element.Edge), "way")]
public abstract class OSMdata
{
public float version { get; set; }
public string generator { get; set; }
public Osm3s osm3s { get; set; }
public Element[] elements { get; set; }
}
public class Osm3s : OSMdata
{
public DateTime timestamp_osm_base { get; set; }
public string copyright { get; set; }
}
public class Element : OSMdata
{
public class Node : Element
{
public string type { get; } = "node";
public long id { get; set; }
public float lat { get; set; }
public float lon { get; set; }
public NodeTags tags { get; set; }
}
public class NodeTags : Node
{
public string highway { get; set; }
public string _ref { get; set; }
}
public class Edge : Element
{
public string type { get; } = "way";
public long id { get; set; }
public long[] nodes { get; set; }
public EdgeTags tags { get; set; }
}
public class EdgeTags : Edge
{
public string highway { get; set; }
public string name { get; set; }
public string cfcc { get; set; }
public string county { get; set; }
public string oneway { get; set; }
}
}
返回:
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
at System.RuntimeType.MakeGenericType(Type[] instantiation)
at JsonSubTypes.JsonSubtypes.CreateCompatibleList(Type targetContainerType, Type elementType)
at JsonSubTypes.JsonSubtypes.ReadArray(JsonReader reader, Type targetType, JsonSerializer serializer)
at JsonSubTypes.JsonSubtypes.ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at newapp.Program.Main(String[] args) in C:\Users\RDCRLDDH\source\repos\newapp\newapp\Program.cs:line 23
虽然我不理解此错误并正在寻找解决方案,但我希望澄清以下几个问题:
问题
我是否正确地构建了 OSMdata 类?我认为我正确地遵循了这些示例,但不确定我是否正确地将类 Node 和 Edge 分配给父类 OSMdata。
反序列化器如何知道将标签"tiger:cfcc" 分配给EdgeTags 中的Cfcc 属性?
【问题讨论】:
-
另一种解决方案是添加一个
NodeOrEdge类并在它们之间编写自定义转换。让库处理丢失的键。 -
而不是加载到一些巨大的
dynamic对象然后手动反序列化,您可以反序列化以使用多态element数组建模。如何查看Json.Net Serialization of Type with Polymorphic Child Object、How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects? 或Deserializing polymorphic json classes without type information using json.net。 -
@dbc 感谢您的阅读!
-
任何时候你使用
dynamic总是认为你自己最有可能是更好的方法 -
@dubbbdan - 不客气。那些回答了你的问题吗?如果不是,您始终可以使用
JToken.ToObject<NodeTags>()或JToken.ToObject<Edge>(),如Deserializing JToken content to an Object 和Converting a JToken (or string) to a given Type 所示。希望您的问题得到这些其他问题之一的回答。
标签: c# json json.net openstreetmap json-deserialization