c# - 使用 JsonReader 而不是 JsonSerializer 时自定义 JsonConverter 不起作用

标签 c# json.net

我有一个类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 ... 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 中失败.

最佳答案

你的问题是,根据documentation , JsonReader.ReadAsString():

Reads the next JSON token from the source as a String.

然而,当JsonConverter.ReadJson()被调用时,读者已经定位到与被反序列化的对象对应的第一个 JSON token 。因此,通过调用 ReadAsString(),您丢弃了该值并尝试读取流中的下一个标记——但是没有标记,因此您抛出异常。

此外,在 ReadJson() 的末尾,您的代码必须将读取器定位到与要转换的对象对应的最后一个 JSON 标记处。因此,在 JSON 只是原始数据的情况下,读者根本不应该有任何进步。

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

StringIdConverter 来自 Json.Net: Serialize/Deserialize property as a value, not as an object 举了一个例子。您可以按如下方式修改它:

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/

相关文章:

c# - 如何使用 Ruby 将时间从 .net 纪元转换为 Unix 纪元中的时间?

javascript - 如何使用jquery清除文本框(使用ConfirmButtonExtender)?

c# - ASP MVC 5 和 Json.NET : action return type

c# - 如何反序列化一个json数据数组

c# - 使用 StringFormat 将字符串添加到 WPF XAML 绑定(bind)

c# - 构建 Windows 资源管理器扩展

c# - 如何将 2 个对象统一为一个连贯的外观?

c# - Newtonsoft JSON 反序列化问题 [将值转换为类型时出错]

json.net - Json转换继承字典的对象

c# - 填充对象异常反序列化抽象类时出现意外的初始标记 'EndObject'