提问者:小点点

在JSON.NET的JSONConverter<>ReadJson()中,为什么Reader..value为空?


我正在尝试为NetTopologySuite几何图形编写一个自定义的JsonConverter。

我的模特:

public class MyModel
{
    public string myName { get; set; }

    [JsonConverter(typeof(MyPolygonConverter))]
    public Polygon myPolygon { get; set; }
}

我的转换器:

public class MyPolygonConverter : JsonConverter<Polygon>
{
    public override Polygon ReadJson(JsonReader reader, Type objectType, Polygon existingValue, 
        bool hasExistingValue, JsonSerializer serializer)
    {
        var geoJson = (string)reader.Value;

        // ... not relevant, because reader.Value is null.
    }
}

我正在做的事:

var deSerialized = JsonConvert.DeserializeObject<MyModel>("{\"myName\":\"My Name\",\"myPolygon\":{\"type\":\"Polygon\",\"coordinates\":[[[-100.0,45.0],[-98.0,45.0],[-99.0,46.0],[-100.0,45.0]]]}}");

发生了什么:

正在调用我的转换器,但Reader.Value为空。

我在网上看到的示例使用(string)reader.value访问需要转换的json字符串。但在我的例子中,reader.value为空。

我应该如何访问我需要转换的JSON字符串?

需要说明的是,我有一个模型类,它包含一个类的属性--Polygon,我在序列化时将其转换为GeoJson,我需要从GeoJson转换回该类。

所以,我的起始json是:

{
    "myName" : "My Name",
    "myPolygon" : {
        "type" : "Polygon",
        "coordinates" : [
            [
                [-100.0, 45.0],
                [-98.0, 45.0],
                [-99.0, 46.0],
                [-100.0, 45.0]
            ]
        ]
    }
}

我需要把“mypolygon”的所有内容都交给我的转换代码。在我看到的简单示例中,reader.value提供了字符串形式的值。在本例中,它不是,很可能是因为“myPolygon”的子对象不是一个值,而是一个复杂的json对象。

我已经有了解析作为单个json字符串提供的值的代码。那么,我如何将孩子作为一个json字符串来获取呢?


共2个答案

匿名用户

我认为您对JsonConverters的工作方式有一个误解。读取器不会给您原始的JSON。它为您提供了一个阅读器,允许您逐个逐个地遍历JSON中的令牌。

reader.value为空,因为您的转换器处理的是对象,而不是字符串,并且在调用转换器时,读取器位于startObject标记上。您需要在循环中调用reader.read(),以在对象中前进以获取属性名称和值,直到到达EndObject令牌。

下面是一个演示该过程的小提琴,尽管它并没有实际填充多边形。https://dotnetfiddle.net/mqe6n5

如果您真的需要转换器中的JSON字符串,您可以从读取器加载一个JObject,然后调用它的ToString()方法:

public override Polygon ReadJson(JsonReader reader, Type objectType, Polygon existingValue, bool hasExistingValue, JsonSerializer serializer)
{
    JObject jo = JObject.Load(reader);
    string json = jo.ToString(Formatting.None);

    Polygon poly = ConvertJsonToPolygon(json);  // your conversion method
    
    return poly;
}

更好的解决方案IMO是使用JObject的功能来实际执行转换。您可以轻松地从JObject中选择值并从中填充Polygon类:

public override Polygon ReadJson(JsonReader reader, Type objectType, Polygon existingValue, bool hasExistingValue, JsonSerializer serializer)
{
    JObject jo = JObject.Load(reader);
    Polygon poly = new Polygon();
    poly.type = (string)jo["type"];
    poly.coordinates = jo["coordinates"].ToObject<double[][][]>(serializer);
    return poly;
}

小提琴:https://dotnetfiddle.net/ofsp1h

匿名用户

正如布莱恩·罗杰斯指出的那样,我看事情的眼光不对。

但是我真的不想一次一个令牌地在JsonReader中循环来构建我需要处理的json对象。

幸运的是,我没必要。JSON.NET已经提供了这样做的工具:

public override Polygon ReadJson(JsonReader reader, Type objectType, 
    Polygon existingValue, bool hasExistingValue, JsonSerializer serializer)
{
    var jObject = JObject.Load(reader);
    var geoJson = jObject.ToString();

    // Work with the geoJson string...
}

注意-当对象不是数组(在我的用例中它永远不会是数组)时,这会起作用。如果要在原地执行某些操作,则可能需要使用JArray。如果您的用例提供了对象可能是数组或对象,那么您可能可以通过检查reader.tokentype==JsonToken.StartObject来区分需要使用哪一个。我没有探索过这一点,因为在我的用例中这是不可能的。