我有一个类Foo及其定义如下的FooConverter

[JsonConverter(typeof(FooConverter))]
public class Foo
{
    public string Something { get; set; }
}

public class FooConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(((Foo)value).Something);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var str = reader.ReadAsString();
        if (str == null)
        {
            throw new JsonSerializationException();
        }
        // return new Foo {Something = serializer.Deserialize<string>(reader)};
        return new Foo {Something = str};
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Foo);
    }
}


序列化工作正常。但是反序列化时:

var foo = JsonConvert.DeserializeObject<Foo>("\"something\"");


它会抛出JsonSerializationException,因为reader.ReadAsString为null。
但是我不明白为什么必须使用null ... reader.ReadAsString可以完美地找到我是否手动执行的操作,如下所示:

var reader = new JsonTextReader(new StringReader("\"something\""));
var str = reader.ReadAsString(); // str is now `something` NOT null


尽管可以通过在FooConverter中使用serializer.Deserialize<string>(reader)修复ReadJson,但我仍然想了解为什么reader.ReadAsStringFooConverter.ReadJson中失败的原因。

最佳答案

您的问题是,根据documentationJsonReader.ReadAsString()


  从源读取下一个JSON令牌作为String。


但是,在调用JsonConverter.ReadJson()时,读取器已经位于与要反序列化的对象相对应的第一个JSON令牌上。因此,通过调用ReadAsString()可以放弃该值,并尝试读取流中的下一个标记-但是没有,因此抛出异常。

此外,在ReadJson()的末尾,您的代码必须已将读取器定位在与要转换的对象相对应的最后一个JSON令牌上。因此,在JSON只是简单的原语的情况下,阅读器根本不应该变得高级。

确保阅读器始终由ReadJson()正确定位的一种简单方法是调用JToken.Load()。这总是使读取器位于已加载令牌的末尾。之后,您可以检查以确保加载了预期的内容。例如,如果JSON的对象应该是字符串,而不是使阅读器的位置不正确,则转换器应抛出异常,而不是使阅读器的位置不正确。

Json.Net: Serialize/Deserialize property as a value, not as an object中的StringIdConverter给出了一个示例。您可以如下修改它:

public class FooConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var token = JToken.Load(reader);
        if (!(token is JValue))
            throw new JsonSerializationException("Token was not a primitive");
        return new Foo { Something = (string)token };
    }

关于c# - 使用JsonReader而不是JsonSerializer时,自定义JsonConverter不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46024882/

10-11 17:16