为什么我的 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 函数。事实上,它根本不起作用!没有失败,但返回的字典包含 RefLocCacheItems,文件路径为 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; }