为什么我的 Newtonsoft.Json 反序列化代码不起作用?
Why my dull Newtonsoft.Json deserialization code does not work?
我有以下习惯JsonConverter
:
using Microsoft.CodeAnalysis.Text;
using Newtonsoft.Json;
using System;
namespace CSTool.Json
{
public class TextSpanJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(TextSpan);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var str = reader.ReadAsString();
var delim = str.IndexOf('.');
var start = int.Parse(str.AsSpan(1, delim - 1));
var end = int.Parse(str.AsSpan(delim + 2, str.Length - delim - 3));
return TextSpan.FromBounds(start, end);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
}
}
它应该有助于(反)序列化以下 class:
using CSTool.Json;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Newtonsoft.Json;
namespace CSTool.ObjectModel
{
public class RefLocCacheItem
{
public string FilePath { get; private set; }
[JsonConverter(typeof(TextSpanJsonConverter))]
public TextSpan TextSpan { get; private set; }
[JsonConverter(typeof(LinePositionSpanJsonConverter))]
public LinePositionSpan LinePositionSpan { get; private set; }
public RefLocCacheItem()
{
}
public RefLocCacheItem(Location o) : this(o.SourceTree.FilePath, o.SourceSpan, o.GetLineSpan().Span)
{
}
public RefLocCacheItem(string filePath, TextSpan textSpan, LinePositionSpan linePositionSpan)
{
FilePath = filePath;
TextSpan = textSpan;
LinePositionSpan = linePositionSpan;
}
}
}
反序列化代码为:
cached = JsonConvert.DeserializeObject<Dictionary<uint, List<RefLocCacheItem>>>(File.ReadAllText(cacheFile));
相应的序列化代码为:
File.WriteAllText(cacheFile, JsonConvert.SerializeObject(cached, Newtonsoft.Json.Formatting.Indented));
这是一个示例 json 文件:
{
"100666494": [],
"100666517": [],
"67111627": [
{
"FilePath": "c:\xyz\tip\MySourceFile.cs",
"TextSpan": "[105331..105379)",
"LinePositionSpan": "(2379,51)-(2379,99)"
}
],
"67111628": [
{
"FilePath": "c:\xyz\tip\MySourceFile.cs",
"TextSpan": "[136762..136795)",
"LinePositionSpan": "(2953,30)-(2953,63)"
}
],
"100666534": []
}
因此,如您所见,序列化工作正常。但是,反序列化代码从不调用转换器的 ReadJson
函数。事实上,它根本不起作用!没有失败,但返回的字典包含 RefLocCacheItem
s,文件路径为 null
,文本跨度为空:
我以前用过很多次Json.Net,现在我不明白我做错了什么。
我使用最新版本 - 13.0.1,但我检查了几个旧版本 - 同样的事情。所以,这是我的错,但错在哪里?
澄清编辑
FilePath
属性 未反序列化。并且与转换器无关。转换器 - ReadJson
方法甚至没有被调用!
问题是您的属性具有私有 setter。因此,Json.Net 会将它们视为只读。您可以将 setter 设置为 public,或者,如果您希望将 setter 设为私有,则可以将 [JsonProperty]
属性添加到 属性 以告诉 Json.Net 可以使用私有 setter:
[JsonProperty]
public string FilePath { get; private set; }
[JsonProperty, JsonConverter(typeof(TextSpanJsonConverter))]
public TextSpan TextSpan { get; private set; }
我有以下习惯JsonConverter
:
using Microsoft.CodeAnalysis.Text;
using Newtonsoft.Json;
using System;
namespace CSTool.Json
{
public class TextSpanJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(TextSpan);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var str = reader.ReadAsString();
var delim = str.IndexOf('.');
var start = int.Parse(str.AsSpan(1, delim - 1));
var end = int.Parse(str.AsSpan(delim + 2, str.Length - delim - 3));
return TextSpan.FromBounds(start, end);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
}
}
它应该有助于(反)序列化以下 class:
using CSTool.Json;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Newtonsoft.Json;
namespace CSTool.ObjectModel
{
public class RefLocCacheItem
{
public string FilePath { get; private set; }
[JsonConverter(typeof(TextSpanJsonConverter))]
public TextSpan TextSpan { get; private set; }
[JsonConverter(typeof(LinePositionSpanJsonConverter))]
public LinePositionSpan LinePositionSpan { get; private set; }
public RefLocCacheItem()
{
}
public RefLocCacheItem(Location o) : this(o.SourceTree.FilePath, o.SourceSpan, o.GetLineSpan().Span)
{
}
public RefLocCacheItem(string filePath, TextSpan textSpan, LinePositionSpan linePositionSpan)
{
FilePath = filePath;
TextSpan = textSpan;
LinePositionSpan = linePositionSpan;
}
}
}
反序列化代码为:
cached = JsonConvert.DeserializeObject<Dictionary<uint, List<RefLocCacheItem>>>(File.ReadAllText(cacheFile));
相应的序列化代码为:
File.WriteAllText(cacheFile, JsonConvert.SerializeObject(cached, Newtonsoft.Json.Formatting.Indented));
这是一个示例 json 文件:
{
"100666494": [],
"100666517": [],
"67111627": [
{
"FilePath": "c:\xyz\tip\MySourceFile.cs",
"TextSpan": "[105331..105379)",
"LinePositionSpan": "(2379,51)-(2379,99)"
}
],
"67111628": [
{
"FilePath": "c:\xyz\tip\MySourceFile.cs",
"TextSpan": "[136762..136795)",
"LinePositionSpan": "(2953,30)-(2953,63)"
}
],
"100666534": []
}
因此,如您所见,序列化工作正常。但是,反序列化代码从不调用转换器的 ReadJson
函数。事实上,它根本不起作用!没有失败,但返回的字典包含 RefLocCacheItem
s,文件路径为 null
,文本跨度为空:
我以前用过很多次Json.Net,现在我不明白我做错了什么。
我使用最新版本 - 13.0.1,但我检查了几个旧版本 - 同样的事情。所以,这是我的错,但错在哪里?
澄清编辑
FilePath
属性 未反序列化。并且与转换器无关。转换器 - ReadJson
方法甚至没有被调用!
问题是您的属性具有私有 setter。因此,Json.Net 会将它们视为只读。您可以将 setter 设置为 public,或者,如果您希望将 setter 设为私有,则可以将 [JsonProperty]
属性添加到 属性 以告诉 Json.Net 可以使用私有 setter:
[JsonProperty]
public string FilePath { get; private set; }
[JsonProperty, JsonConverter(typeof(TextSpanJsonConverter))]
public TextSpan TextSpan { get; private set; }